Rename `id_source` to `id_salt` (#5025)

* Closes <https://github.com/emilk/egui/issues/5020 >
* [x] I have followed the instructions in the PR template
This commit is contained in:
Nicolas 2024-09-02 09:29:01 +02:00 committed by GitHub
parent edea5a40b9
commit be944f0915
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 169 additions and 121 deletions

View File

@ -372,7 +372,7 @@ pub struct CollapsingHeader {
text: WidgetText, text: WidgetText,
default_open: bool, default_open: bool,
open: Option<bool>, open: Option<bool>,
id_source: Id, id_salt: Id,
enabled: bool, enabled: bool,
selectable: bool, selectable: bool,
selected: bool, selected: bool,
@ -386,15 +386,15 @@ impl CollapsingHeader {
/// The label is used as an [`Id`] source. /// The label is used as an [`Id`] source.
/// If the label is unique and static this is fine, /// If the label is unique and static this is fine,
/// but if it changes or there are several [`CollapsingHeader`] with the same title /// but if it changes or there are several [`CollapsingHeader`] with the same title
/// you need to provide a unique id source with [`Self::id_source`]. /// you need to provide a unique id source with [`Self::id_salt`].
pub fn new(text: impl Into<WidgetText>) -> Self { pub fn new(text: impl Into<WidgetText>) -> Self {
let text = text.into(); let text = text.into();
let id_source = Id::new(text.text()); let id_salt = Id::new(text.text());
Self { Self {
text, text,
default_open: false, default_open: false,
open: None, open: None,
id_source, id_salt,
enabled: true, enabled: true,
selectable: false, selectable: false,
selected: false, selected: false,
@ -425,8 +425,17 @@ impl CollapsingHeader {
/// Explicitly set the source of the [`Id`] of this widget, instead of using title label. /// Explicitly set the source of the [`Id`] of this widget, instead of using title label.
/// This is useful if the title label is dynamic or not unique. /// This is useful if the title label is dynamic or not unique.
#[inline] #[inline]
pub fn id_source(mut self, id_source: impl Hash) -> Self { pub fn id_salt(mut self, id_salt: impl Hash) -> Self {
self.id_source = Id::new(id_source); self.id_salt = Id::new(id_salt);
self
}
/// Explicitly set the source of the [`Id`] of this widget, instead of using title label.
/// This is useful if the title label is dynamic or not unique.
#[deprecated = "Renamed id_salt"]
#[inline]
pub fn id_source(mut self, id_salt: impl Hash) -> Self {
self.id_salt = Id::new(id_salt);
self self
} }
@ -494,7 +503,7 @@ impl CollapsingHeader {
text, text,
default_open, default_open,
open, open,
id_source, id_salt,
enabled: _, enabled: _,
selectable, selectable,
selected, selected,
@ -503,7 +512,7 @@ impl CollapsingHeader {
// TODO(emilk): horizontal layout, with icon and text as labels. Insert background behind using Frame. // TODO(emilk): horizontal layout, with icon and text as labels. Insert background behind using Frame.
let id = ui.make_persistent_id(id_source); let id = ui.make_persistent_id(id_salt);
let button_padding = ui.spacing().button_padding; let button_padding = ui.spacing().button_padding;
let available = ui.available_rect_before_wrap(); let available = ui.available_rect_before_wrap();

View File

@ -38,7 +38,7 @@ pub type IconPainter = Box<dyn FnOnce(&Ui, Rect, &WidgetVisuals, bool, AboveOrBe
/// ``` /// ```
#[must_use = "You should call .show*"] #[must_use = "You should call .show*"]
pub struct ComboBox { pub struct ComboBox {
id_source: Id, id_salt: Id,
label: Option<WidgetText>, label: Option<WidgetText>,
selected_text: WidgetText, selected_text: WidgetText,
width: Option<f32>, width: Option<f32>,
@ -49,9 +49,9 @@ pub struct ComboBox {
impl ComboBox { impl ComboBox {
/// Create new [`ComboBox`] with id and label /// Create new [`ComboBox`] with id and label
pub fn new(id_source: impl std::hash::Hash, label: impl Into<WidgetText>) -> Self { pub fn new(id_salt: impl std::hash::Hash, label: impl Into<WidgetText>) -> Self {
Self { Self {
id_source: Id::new(id_source), id_salt: Id::new(id_salt),
label: Some(label.into()), label: Some(label.into()),
selected_text: Default::default(), selected_text: Default::default(),
width: None, width: None,
@ -65,7 +65,7 @@ impl ComboBox {
pub fn from_label(label: impl Into<WidgetText>) -> Self { pub fn from_label(label: impl Into<WidgetText>) -> Self {
let label = label.into(); let label = label.into();
Self { Self {
id_source: Id::new(label.text()), id_salt: Id::new(label.text()),
label: Some(label), label: Some(label),
selected_text: Default::default(), selected_text: Default::default(),
width: None, width: None,
@ -76,9 +76,9 @@ impl ComboBox {
} }
/// Without label. /// Without label.
pub fn from_id_source(id_source: impl std::hash::Hash) -> Self { pub fn from_id_salt(id_salt: impl std::hash::Hash) -> Self {
Self { Self {
id_source: Id::new(id_source), id_salt: Id::new(id_salt),
label: Default::default(), label: Default::default(),
selected_text: Default::default(), selected_text: Default::default(),
width: None, width: None,
@ -88,6 +88,12 @@ impl ComboBox {
} }
} }
/// Without label.
#[deprecated = "Renamed id_salt"]
pub fn from_id_source(id_salt: impl std::hash::Hash) -> Self {
Self::from_id_salt(id_salt)
}
/// Set the outer width of the button and menu. /// Set the outer width of the button and menu.
/// ///
/// Default is [`Spacing::combo_width`]. /// Default is [`Spacing::combo_width`].
@ -138,7 +144,7 @@ impl ComboBox {
/// )); /// ));
/// } /// }
/// ///
/// egui::ComboBox::from_id_source("my-combobox") /// egui::ComboBox::from_id_salt("my-combobox")
/// .selected_text(text) /// .selected_text(text)
/// .icon(filled_triangle) /// .icon(filled_triangle)
/// .show_ui(ui, |_ui| {}); /// .show_ui(ui, |_ui| {});
@ -195,7 +201,7 @@ impl ComboBox {
menu_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>, menu_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
) -> InnerResponse<Option<R>> { ) -> InnerResponse<Option<R>> {
let Self { let Self {
id_source, id_salt,
label, label,
selected_text, selected_text,
width, width,
@ -204,7 +210,7 @@ impl ComboBox {
wrap_mode, wrap_mode,
} = self; } = self;
let button_id = ui.make_persistent_id(id_source); let button_id = ui.make_persistent_id(id_salt);
ui.horizontal(|ui| { ui.horizontal(|ui| {
let mut ir = combo_box_dyn( let mut ir = combo_box_dyn(

View File

@ -266,7 +266,7 @@ impl SidePanel {
let mut panel_ui = ui.new_child( let mut panel_ui = ui.new_child(
UiBuilder::new() UiBuilder::new()
.id_source(id) .id_salt(id)
.ui_stack_info(UiStackInfo::new(match side { .ui_stack_info(UiStackInfo::new(match side {
Side::Left => UiKind::LeftPanel, Side::Left => UiKind::LeftPanel,
Side::Right => UiKind::RightPanel, Side::Right => UiKind::RightPanel,
@ -761,7 +761,7 @@ impl TopBottomPanel {
let mut panel_ui = ui.new_child( let mut panel_ui = ui.new_child(
UiBuilder::new() UiBuilder::new()
.id_source(id) .id_salt(id)
.ui_stack_info(UiStackInfo::new(match side { .ui_stack_info(UiStackInfo::new(match side {
TopBottomSide::Top => UiKind::TopPanel, TopBottomSide::Top => UiKind::TopPanel,
TopBottomSide::Bottom => UiKind::BottomPanel, TopBottomSide::Bottom => UiKind::BottomPanel,

View File

@ -34,7 +34,7 @@ impl State {
#[must_use = "You should call .show()"] #[must_use = "You should call .show()"]
pub struct Resize { pub struct Resize {
id: Option<Id>, id: Option<Id>,
id_source: Option<Id>, id_salt: Option<Id>,
/// If false, we are no enabled /// If false, we are no enabled
resizable: Vec2b, resizable: Vec2b,
@ -51,7 +51,7 @@ impl Default for Resize {
fn default() -> Self { fn default() -> Self {
Self { Self {
id: None, id: None,
id_source: None, id_salt: None,
resizable: Vec2b::TRUE, resizable: Vec2b::TRUE,
min_size: Vec2::splat(16.0), min_size: Vec2::splat(16.0),
max_size: Vec2::splat(f32::INFINITY), max_size: Vec2::splat(f32::INFINITY),
@ -71,8 +71,15 @@ impl Resize {
/// A source for the unique [`Id`], e.g. `.id_source("second_resize_area")` or `.id_source(loop_index)`. /// A source for the unique [`Id`], e.g. `.id_source("second_resize_area")` or `.id_source(loop_index)`.
#[inline] #[inline]
pub fn id_source(mut self, id_source: impl std::hash::Hash) -> Self { #[deprecated = "Renamed id_salt"]
self.id_source = Some(Id::new(id_source)); pub fn id_source(self, id_salt: impl std::hash::Hash) -> Self {
self.id_salt(id_salt)
}
/// A source for the unique [`Id`], e.g. `.id_salt("second_resize_area")` or `.id_salt(loop_index)`.
#[inline]
pub fn id_salt(mut self, id_salt: impl std::hash::Hash) -> Self {
self.id_salt = Some(Id::new(id_salt));
self self
} }
@ -201,8 +208,8 @@ impl Resize {
fn begin(&mut self, ui: &mut Ui) -> Prepared { fn begin(&mut self, ui: &mut Ui) -> Prepared {
let position = ui.available_rect_before_wrap().min; let position = ui.available_rect_before_wrap().min;
let id = self.id.unwrap_or_else(|| { let id = self.id.unwrap_or_else(|| {
let id_source = self.id_source.unwrap_or_else(|| Id::new("resize")); let id_salt = self.id_salt.unwrap_or_else(|| Id::new("resize"));
ui.make_persistent_id(id_source) ui.make_persistent_id(id_salt)
}); });
let mut state = State::load(ui.ctx(), id).unwrap_or_else(|| { let mut state = State::load(ui.ctx(), id).unwrap_or_else(|| {

View File

@ -171,7 +171,7 @@ pub struct ScrollArea {
max_size: Vec2, max_size: Vec2,
min_scrolled_size: Vec2, min_scrolled_size: Vec2,
scroll_bar_visibility: ScrollBarVisibility, scroll_bar_visibility: ScrollBarVisibility,
id_source: Option<Id>, id_salt: Option<Id>,
offset_x: Option<f32>, offset_x: Option<f32>,
offset_y: Option<f32>, offset_y: Option<f32>,
@ -223,7 +223,7 @@ impl ScrollArea {
max_size: Vec2::INFINITY, max_size: Vec2::INFINITY,
min_scrolled_size: Vec2::splat(64.0), min_scrolled_size: Vec2::splat(64.0),
scroll_bar_visibility: Default::default(), scroll_bar_visibility: Default::default(),
id_source: None, id_salt: None,
offset_x: None, offset_x: None,
offset_y: None, offset_y: None,
scrolling_enabled: true, scrolling_enabled: true,
@ -290,8 +290,15 @@ impl ScrollArea {
/// A source for the unique [`Id`], e.g. `.id_source("second_scroll_area")` or `.id_source(loop_index)`. /// A source for the unique [`Id`], e.g. `.id_source("second_scroll_area")` or `.id_source(loop_index)`.
#[inline] #[inline]
pub fn id_source(mut self, id_source: impl std::hash::Hash) -> Self { #[deprecated = "Renamed id_salt"]
self.id_source = Some(Id::new(id_source)); pub fn id_source(self, id_salt: impl std::hash::Hash) -> Self {
self.id_salt(id_salt)
}
/// A source for the unique [`Id`], e.g. `.id_salt("second_scroll_area")` or `.id_salt(loop_index)`.
#[inline]
pub fn id_salt(mut self, id_salt: impl std::hash::Hash) -> Self {
self.id_salt = Some(Id::new(id_salt));
self self
} }
@ -490,7 +497,7 @@ impl ScrollArea {
max_size, max_size,
min_scrolled_size, min_scrolled_size,
scroll_bar_visibility, scroll_bar_visibility,
id_source, id_salt,
offset_x, offset_x,
offset_y, offset_y,
scrolling_enabled, scrolling_enabled,
@ -502,8 +509,8 @@ impl ScrollArea {
let ctx = ui.ctx().clone(); let ctx = ui.ctx().clone();
let scrolling_enabled = scrolling_enabled && ui.is_enabled(); let scrolling_enabled = scrolling_enabled && ui.is_enabled();
let id_source = id_source.unwrap_or_else(|| Id::new("scroll_area")); let id_salt = id_salt.unwrap_or_else(|| Id::new("scroll_area"));
let id = ui.make_persistent_id(id_source); let id = ui.make_persistent_id(id_salt);
ctx.check_for_id_clash( ctx.check_for_id_clash(
id, id,
Rect::from_min_size(ui.available_rect_before_wrap().min, Vec2::ZERO), Rect::from_min_size(ui.available_rect_before_wrap().min, Vec2::ZERO),

View File

@ -1022,7 +1022,7 @@ impl Context {
tooltip_pos, tooltip_pos,
format!("Widget is {} this text.\n\n\ format!("Widget is {} this text.\n\n\
ID clashes happens when things like Windows or CollapsingHeaders share names,\n\ ID clashes happens when things like Windows or CollapsingHeaders share names,\n\
or when things like Plot and Grid:s aren't given unique id_source:s.\n\n\ or when things like Plot and Grid:s aren't given unique id_salt:s.\n\n\
Sometimes the solution is to use ui.push_id.", Sometimes the solution is to use ui.push_id.",
if below { "above" } else { "below" }) if below { "above" } else { "below" })
); );

View File

@ -299,7 +299,7 @@ impl GridLayout {
/// ``` /// ```
#[must_use = "You should call .show()"] #[must_use = "You should call .show()"]
pub struct Grid { pub struct Grid {
id_source: Id, id_salt: Id,
num_columns: Option<usize>, num_columns: Option<usize>,
min_col_width: Option<f32>, min_col_width: Option<f32>,
min_row_height: Option<f32>, min_row_height: Option<f32>,
@ -311,9 +311,9 @@ pub struct Grid {
impl Grid { impl Grid {
/// Create a new [`Grid`] with a locally unique identifier. /// Create a new [`Grid`] with a locally unique identifier.
pub fn new(id_source: impl std::hash::Hash) -> Self { pub fn new(id_salt: impl std::hash::Hash) -> Self {
Self { Self {
id_source: Id::new(id_source), id_salt: Id::new(id_salt),
num_columns: None, num_columns: None,
min_col_width: None, min_col_width: None,
min_row_height: None, min_row_height: None,
@ -407,7 +407,7 @@ impl Grid {
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>, add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
) -> InnerResponse<R> { ) -> InnerResponse<R> {
let Self { let Self {
id_source, id_salt,
num_columns, num_columns,
min_col_width, min_col_width,
min_row_height, min_row_height,
@ -423,7 +423,7 @@ impl Grid {
color_picker = Some(Box::new(striped_row_color)); color_picker = Some(Box::new(striped_row_color));
} }
let id = ui.make_persistent_id(id_source); let id = ui.make_persistent_id(id_salt);
let prev_state = State::load(ui.ctx(), id); let prev_state = State::load(ui.ctx(), id);
// Each grid cell is aligned LEFT_CENTER. // Each grid cell is aligned LEFT_CENTER.

View File

@ -1537,7 +1537,7 @@ impl Style {
ui.end_row(); ui.end_row();
ui.label("Override text style"); ui.label("Override text style");
crate::ComboBox::from_id_source("Override text style") crate::ComboBox::from_id_salt("Override text style")
.selected_text(match override_text_style { .selected_text(match override_text_style {
None => "None".to_owned(), None => "None".to_owned(),
Some(override_text_style) => override_text_style.to_string(), Some(override_text_style) => override_text_style.to_string(),
@ -1554,7 +1554,7 @@ impl Style {
ui.end_row(); ui.end_row();
ui.label("Text style of DragValue"); ui.label("Text style of DragValue");
crate::ComboBox::from_id_source("drag_value_text_style") crate::ComboBox::from_id_salt("drag_value_text_style")
.selected_text(drag_value_text_style.to_string()) .selected_text(drag_value_text_style.to_string())
.show_ui(ui, |ui| { .show_ui(ui, |ui| {
let all_text_styles = ui.style().text_styles(); let all_text_styles = ui.style().text_styles();
@ -1567,7 +1567,7 @@ impl Style {
ui.end_row(); ui.end_row();
ui.label("Text Wrap Mode"); ui.label("Text Wrap Mode");
crate::ComboBox::from_id_source("text_wrap_mode") crate::ComboBox::from_id_salt("text_wrap_mode")
.selected_text(format!("{wrap_mode:?}")) .selected_text(format!("{wrap_mode:?}"))
.show_ui(ui, |ui| { .show_ui(ui, |ui| {
let all_wrap_mode: Vec<Option<TextWrapMode>> = vec![ let all_wrap_mode: Vec<Option<TextWrapMode>> = vec![

View File

@ -63,7 +63,7 @@ pub struct Ui {
/// and the value is increment with each added child widget. /// and the value is increment with each added child widget.
/// This works as an Id source only as long as new widgets aren't added or removed. /// This works as an Id source only as long as new widgets aren't added or removed.
/// They are therefore only good for Id:s that has no state. /// They are therefore only good for Id:s that has no state.
next_auto_id_source: u64, next_auto_id_salt: u64,
/// Specifies paint layer, clip rectangle and a reference to [`Context`]. /// Specifies paint layer, clip rectangle and a reference to [`Context`].
painter: Painter, painter: Painter,
@ -101,7 +101,7 @@ impl Ui {
/// [`crate::SidePanel`], [`crate::TopBottomPanel`], [`crate::CentralPanel`], [`crate::Window`] or [`crate::Area`]. /// [`crate::SidePanel`], [`crate::TopBottomPanel`], [`crate::CentralPanel`], [`crate::Window`] or [`crate::Area`].
pub fn new(ctx: Context, layer_id: LayerId, id: Id, ui_builder: UiBuilder) -> Self { pub fn new(ctx: Context, layer_id: LayerId, id: Id, ui_builder: UiBuilder) -> Self {
let UiBuilder { let UiBuilder {
id_source, id_salt,
ui_stack_info, ui_stack_info,
max_rect, max_rect,
layout, layout,
@ -112,8 +112,8 @@ impl Ui {
} = ui_builder; } = ui_builder;
debug_assert!( debug_assert!(
id_source.is_none(), id_salt.is_none(),
"Top-level Ui:s should not have an id_source" "Top-level Ui:s should not have an id_salt"
); );
let max_rect = max_rect.unwrap_or_else(|| ctx.screen_rect()); let max_rect = max_rect.unwrap_or_else(|| ctx.screen_rect());
@ -134,7 +134,7 @@ impl Ui {
}; };
let mut ui = Ui { let mut ui = Ui {
id, id,
next_auto_id_source: id.with("auto").value(), next_auto_id_salt: id.with("auto").value(),
painter: Painter::new(ctx, layer_id, clip_rect), painter: Painter::new(ctx, layer_id, clip_rect),
style, style,
placer, placer,
@ -197,12 +197,12 @@ impl Ui {
&mut self, &mut self,
max_rect: Rect, max_rect: Rect,
layout: Layout, layout: Layout,
id_source: impl Hash, id_salt: impl Hash,
ui_stack_info: Option<UiStackInfo>, ui_stack_info: Option<UiStackInfo>,
) -> Self { ) -> Self {
self.new_child( self.new_child(
UiBuilder::new() UiBuilder::new()
.id_source(id_source) .id_salt(id_salt)
.max_rect(max_rect) .max_rect(max_rect)
.layout(layout) .layout(layout)
.ui_stack_info(ui_stack_info.unwrap_or_default()), .ui_stack_info(ui_stack_info.unwrap_or_default()),
@ -212,7 +212,7 @@ impl Ui {
/// Create a child `Ui` with the properties of the given builder. /// Create a child `Ui` with the properties of the given builder.
pub fn new_child(&mut self, ui_builder: UiBuilder) -> Self { pub fn new_child(&mut self, ui_builder: UiBuilder) -> Self {
let UiBuilder { let UiBuilder {
id_source, id_salt,
ui_stack_info, ui_stack_info,
max_rect, max_rect,
layout, layout,
@ -224,7 +224,7 @@ impl Ui {
let mut painter = self.painter.clone(); let mut painter = self.painter.clone();
let id_source = id_source.unwrap_or_else(|| Id::from("child")); let id_salt = id_salt.unwrap_or_else(|| Id::from("child"));
let max_rect = max_rect.unwrap_or_else(|| self.available_rect_before_wrap()); let max_rect = max_rect.unwrap_or_else(|| self.available_rect_before_wrap());
let mut layout = layout.unwrap_or(*self.layout()); let mut layout = layout.unwrap_or(*self.layout());
let invisible = invisible || sizing_pass; let invisible = invisible || sizing_pass;
@ -245,10 +245,10 @@ impl Ui {
} }
debug_assert!(!max_rect.any_nan()); debug_assert!(!max_rect.any_nan());
let new_id = self.id.with(id_source); let new_id = self.id.with(id_salt);
let next_auto_id_source = new_id.with(self.next_auto_id_source).value(); let next_auto_id_salt = new_id.with(self.next_auto_id_salt).value();
self.next_auto_id_source = self.next_auto_id_source.wrapping_add(1); self.next_auto_id_salt = self.next_auto_id_salt.wrapping_add(1);
let placer = Placer::new(max_rect, layout); let placer = Placer::new(max_rect, layout);
let ui_stack = UiStack { let ui_stack = UiStack {
@ -261,7 +261,7 @@ impl Ui {
}; };
let child_ui = Ui { let child_ui = Ui {
id: new_id, id: new_id,
next_auto_id_source, next_auto_id_salt,
painter, painter,
style, style,
placer, placer,
@ -918,29 +918,29 @@ impl Ui {
/// # [`Id`] creation /// # [`Id`] creation
impl Ui { impl Ui {
/// Use this to generate widget ids for widgets that have persistent state in [`Memory`]. /// Use this to generate widget ids for widgets that have persistent state in [`Memory`].
pub fn make_persistent_id<IdSource>(&self, id_source: IdSource) -> Id pub fn make_persistent_id<IdSource>(&self, id_salt: IdSource) -> Id
where where
IdSource: Hash, IdSource: Hash,
{ {
self.id.with(&id_source) self.id.with(&id_salt)
} }
/// This is the `Id` that will be assigned to the next widget added to this `Ui`. /// This is the `Id` that will be assigned to the next widget added to this `Ui`.
pub fn next_auto_id(&self) -> Id { pub fn next_auto_id(&self) -> Id {
Id::new(self.next_auto_id_source) Id::new(self.next_auto_id_salt)
} }
/// Same as `ui.next_auto_id().with(id_source)` /// Same as `ui.next_auto_id().with(id_salt)`
pub fn auto_id_with<IdSource>(&self, id_source: IdSource) -> Id pub fn auto_id_with<IdSource>(&self, id_salt: IdSource) -> Id
where where
IdSource: Hash, IdSource: Hash,
{ {
Id::new(self.next_auto_id_source).with(id_source) Id::new(self.next_auto_id_salt).with(id_salt)
} }
/// Pretend like `count` widgets have been allocated. /// Pretend like `count` widgets have been allocated.
pub fn skip_ahead_auto_ids(&mut self, count: usize) { pub fn skip_ahead_auto_ids(&mut self, count: usize) {
self.next_auto_id_source = self.next_auto_id_source.wrapping_add(count as u64); self.next_auto_id_salt = self.next_auto_id_salt.wrapping_add(count as u64);
} }
} }
@ -1110,8 +1110,8 @@ impl Ui {
} }
} }
let id = Id::new(self.next_auto_id_source); let id = Id::new(self.next_auto_id_salt);
self.next_auto_id_source = self.next_auto_id_source.wrapping_add(1); self.next_auto_id_salt = self.next_auto_id_salt.wrapping_add(1);
(id, rect) (id, rect)
} }
@ -1148,8 +1148,8 @@ impl Ui {
let item_spacing = self.spacing().item_spacing; let item_spacing = self.spacing().item_spacing;
self.placer.advance_after_rects(rect, rect, item_spacing); self.placer.advance_after_rects(rect, rect, item_spacing);
let id = Id::new(self.next_auto_id_source); let id = Id::new(self.next_auto_id_salt);
self.next_auto_id_source = self.next_auto_id_source.wrapping_add(1); self.next_auto_id_salt = self.next_auto_id_salt.wrapping_add(1);
id id
} }
@ -2086,13 +2086,10 @@ impl Ui {
/// ``` /// ```
pub fn push_id<R>( pub fn push_id<R>(
&mut self, &mut self,
id_source: impl Hash, id_salt: impl Hash,
add_contents: impl FnOnce(&mut Ui) -> R, add_contents: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<R> { ) -> InnerResponse<R> {
self.scope_dyn( self.scope_dyn(UiBuilder::new().id_salt(id_salt), Box::new(add_contents))
UiBuilder::new().id_source(id_source),
Box::new(add_contents),
)
} }
/// Push another level onto the [`UiStack`]. /// Push another level onto the [`UiStack`].
@ -2141,9 +2138,9 @@ impl Ui {
ui_builder: UiBuilder, ui_builder: UiBuilder,
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>, add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
) -> InnerResponse<R> { ) -> InnerResponse<R> {
let next_auto_id_source = self.next_auto_id_source; let next_auto_id_salt = self.next_auto_id_salt;
let mut child_ui = self.new_child(ui_builder); let mut child_ui = self.new_child(ui_builder);
self.next_auto_id_source = next_auto_id_source; // HACK: we want `scope` to only increment this once, so that `ui.scope` is equivalent to `ui.allocate_space`. self.next_auto_id_salt = next_auto_id_salt; // HACK: we want `scope` to only increment this once, so that `ui.scope` is equivalent to `ui.allocate_space`.
let ret = add_contents(&mut child_ui); let ret = add_contents(&mut child_ui);
let response = self.allocate_rect(child_ui.min_rect(), Sense::hover()); let response = self.allocate_rect(child_ui.min_rect(), Sense::hover());
InnerResponse::new(ret, response) InnerResponse::new(ret, response)
@ -2164,7 +2161,7 @@ impl Ui {
/// A [`CollapsingHeader`] that starts out collapsed. /// A [`CollapsingHeader`] that starts out collapsed.
/// ///
/// The name must be unique within the current parent, /// The name must be unique within the current parent,
/// or you need to use [`CollapsingHeader::id_source`]. /// or you need to use [`CollapsingHeader::id_salt`].
pub fn collapsing<R>( pub fn collapsing<R>(
&mut self, &mut self,
heading: impl Into<WidgetText>, heading: impl Into<WidgetText>,
@ -2175,20 +2172,20 @@ impl Ui {
/// Create a child ui which is indented to the right. /// Create a child ui which is indented to the right.
/// ///
/// The `id_source` here be anything at all. /// The `id_salt` here be anything at all.
// TODO(emilk): remove `id_source` argument? // TODO(emilk): remove `id_salt` argument?
#[inline] #[inline]
pub fn indent<R>( pub fn indent<R>(
&mut self, &mut self,
id_source: impl Hash, id_salt: impl Hash,
add_contents: impl FnOnce(&mut Ui) -> R, add_contents: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<R> { ) -> InnerResponse<R> {
self.indent_dyn(id_source, Box::new(add_contents)) self.indent_dyn(id_salt, Box::new(add_contents))
} }
fn indent_dyn<'c, R>( fn indent_dyn<'c, R>(
&mut self, &mut self,
id_source: impl Hash, id_salt: impl Hash,
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>, add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
) -> InnerResponse<R> { ) -> InnerResponse<R> {
assert!( assert!(
@ -2201,8 +2198,7 @@ impl Ui {
let mut child_rect = self.placer.available_rect_before_wrap(); let mut child_rect = self.placer.available_rect_before_wrap();
child_rect.min.x += indent; child_rect.min.x += indent;
let mut child_ui = let mut child_ui = self.new_child(UiBuilder::new().id_salt(id_salt).max_rect(child_rect));
self.new_child(UiBuilder::new().id_source(id_source).max_rect(child_rect));
let ret = add_contents(&mut child_ui); let ret = add_contents(&mut child_ui);
let left_vline = self.visuals().indent_has_left_vline; let left_vline = self.visuals().indent_has_left_vline;

View File

@ -13,7 +13,7 @@ use crate::Ui;
#[must_use] #[must_use]
#[derive(Clone, Default)] #[derive(Clone, Default)]
pub struct UiBuilder { pub struct UiBuilder {
pub id_source: Option<Id>, pub id_salt: Option<Id>,
pub ui_stack_info: UiStackInfo, pub ui_stack_info: UiStackInfo,
pub max_rect: Option<Rect>, pub max_rect: Option<Rect>,
pub layout: Option<Layout>, pub layout: Option<Layout>,
@ -29,14 +29,14 @@ impl UiBuilder {
Self::default() Self::default()
} }
/// Seed the child `Ui` with this `id_source`, which will be mixed /// Seed the child `Ui` with this `id_salt`, which will be mixed
/// with the [`Ui::id`] of the parent. /// with the [`Ui::id`] of the parent.
/// ///
/// You should give each [`Ui`] an `id_source` that is unique /// You should give each [`Ui`] an `id_salt` that is unique
/// within the parent, or give it none at all. /// within the parent, or give it none at all.
#[inline] #[inline]
pub fn id_source(mut self, id_source: impl Hash) -> Self { pub fn id_salt(mut self, id_salt: impl Hash) -> Self {
self.id_source = Some(Id::new(id_source)); self.id_salt = Some(Id::new(id_salt));
self self
} }

View File

@ -66,7 +66,7 @@ pub struct TextEdit<'t> {
hint_text: WidgetText, hint_text: WidgetText,
hint_text_font: Option<FontSelection>, hint_text_font: Option<FontSelection>,
id: Option<Id>, id: Option<Id>,
id_source: Option<Id>, id_salt: Option<Id>,
font_selection: FontSelection, font_selection: FontSelection,
text_color: Option<Color32>, text_color: Option<Color32>,
layouter: Option<&'t mut dyn FnMut(&Ui, &str, f32) -> Arc<Galley>>, layouter: Option<&'t mut dyn FnMut(&Ui, &str, f32) -> Arc<Galley>>,
@ -118,7 +118,7 @@ impl<'t> TextEdit<'t> {
hint_text: Default::default(), hint_text: Default::default(),
hint_text_font: None, hint_text_font: None,
id: None, id: None,
id_source: None, id_salt: None,
font_selection: Default::default(), font_selection: Default::default(),
text_color: None, text_color: None,
layouter: None, layouter: None,
@ -162,8 +162,14 @@ impl<'t> TextEdit<'t> {
/// A source for the unique [`Id`], e.g. `.id_source("second_text_edit_field")` or `.id_source(loop_index)`. /// A source for the unique [`Id`], e.g. `.id_source("second_text_edit_field")` or `.id_source(loop_index)`.
#[inline] #[inline]
pub fn id_source(mut self, id_source: impl std::hash::Hash) -> Self { pub fn id_source(self, id_salt: impl std::hash::Hash) -> Self {
self.id_source = Some(Id::new(id_source)); self.id_salt(id_salt)
}
/// A source for the unique [`Id`], e.g. `.id_salt("second_text_edit_field")` or `.id_salt(loop_index)`.
#[inline]
pub fn id_salt(mut self, id_salt: impl std::hash::Hash) -> Self {
self.id_salt = Some(Id::new(id_salt));
self self
} }
@ -453,7 +459,7 @@ impl<'t> TextEdit<'t> {
hint_text, hint_text,
hint_text_font, hint_text_font,
id, id,
id_source, id_salt,
font_selection, font_selection,
text_color, text_color,
layouter, layouter,
@ -518,8 +524,8 @@ impl<'t> TextEdit<'t> {
let rect = outer_rect - margin; // inner rect (excluding frame/margin). let rect = outer_rect - margin; // inner rect (excluding frame/margin).
let id = id.unwrap_or_else(|| { let id = id.unwrap_or_else(|| {
if let Some(id_source) = id_source { if let Some(id_salt) = id_salt {
ui.make_persistent_id(id_source) ui.make_persistent_id(id_salt)
} else { } else {
auto_id // Since we are only storing the cursor a persistent Id is not super important auto_id // Since we are only storing the cursor a persistent Id is not super important
} }

View File

@ -297,7 +297,7 @@ fn integration_ui(ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
} }
let mut size = None; let mut size = None;
egui::ComboBox::from_id_source("viewport-size-combo") egui::ComboBox::from_id_salt("viewport-size-combo")
.selected_text("Resize to…") .selected_text("Resize to…")
.show_ui(ui, |ui| { .show_ui(ui, |ui| {
ui.selectable_value( ui.selectable_value(

View File

@ -58,10 +58,10 @@ impl EasyMarkEditor {
if self.show_rendered { if self.show_rendered {
ui.columns(2, |columns| { ui.columns(2, |columns| {
ScrollArea::vertical() ScrollArea::vertical()
.id_source("source") .id_salt("source")
.show(&mut columns[0], |ui| self.editor_ui(ui)); .show(&mut columns[0], |ui| self.editor_ui(ui));
ScrollArea::vertical() ScrollArea::vertical()
.id_source("rendered") .id_salt("rendered")
.show(&mut columns[1], |ui| { .show(&mut columns[1], |ui| {
// TODO(emilk): we can save some more CPU by caching the rendered output. // TODO(emilk): we can save some more CPU by caching the rendered output.
crate::easy_mark::easy_mark(ui, &self.code); crate::easy_mark::easy_mark(ui, &self.code);
@ -69,7 +69,7 @@ impl EasyMarkEditor {
}); });
} else { } else {
ScrollArea::vertical() ScrollArea::vertical()
.id_source("source") .id_salt("source")
.show(ui, |ui| self.editor_ui(ui)); .show(ui, |ui| self.editor_ui(ui));
} }
} }

View File

@ -11,7 +11,7 @@ pub(crate) struct DatePickerButtonState {
/// Shows a date, and will open a date picker popup when clicked. /// Shows a date, and will open a date picker popup when clicked.
pub struct DatePickerButton<'a> { pub struct DatePickerButton<'a> {
selection: &'a mut NaiveDate, selection: &'a mut NaiveDate,
id_source: Option<&'a str>, id_salt: Option<&'a str>,
combo_boxes: bool, combo_boxes: bool,
arrows: bool, arrows: bool,
calendar: bool, calendar: bool,
@ -25,7 +25,7 @@ impl<'a> DatePickerButton<'a> {
pub fn new(selection: &'a mut NaiveDate) -> Self { pub fn new(selection: &'a mut NaiveDate) -> Self {
Self { Self {
selection, selection,
id_source: None, id_salt: None,
combo_boxes: true, combo_boxes: true,
arrows: true, arrows: true,
calendar: true, calendar: true,
@ -39,11 +39,19 @@ impl<'a> DatePickerButton<'a> {
/// Add id source. /// Add id source.
/// Must be set if multiple date picker buttons are in the same Ui. /// Must be set if multiple date picker buttons are in the same Ui.
#[inline] #[inline]
pub fn id_source(mut self, id_source: &'a str) -> Self { pub fn id_salt(mut self, id_salt: &'a str) -> Self {
self.id_source = Some(id_source); self.id_salt = Some(id_salt);
self self
} }
/// Add id source.
/// Must be set if multiple date picker buttons are in the same Ui.
#[inline]
#[deprecated = "Renamed id_salt"]
pub fn id_source(self, id_salt: &'a str) -> Self {
self.id_salt(id_salt)
}
/// Show combo boxes in date picker popup. (Default: true) /// Show combo boxes in date picker popup. (Default: true)
#[inline] #[inline]
pub fn combo_boxes(mut self, combo_boxes: bool) -> Self { pub fn combo_boxes(mut self, combo_boxes: bool) -> Self {
@ -97,7 +105,7 @@ impl<'a> DatePickerButton<'a> {
impl<'a> Widget for DatePickerButton<'a> { impl<'a> Widget for DatePickerButton<'a> {
fn ui(self, ui: &mut Ui) -> egui::Response { fn ui(self, ui: &mut Ui) -> egui::Response {
let id = ui.make_persistent_id(self.id_source); let id = ui.make_persistent_id(self.id_salt);
let mut button_state = ui let mut button_state = ui
.data_mut(|data| data.get_persisted::<DatePickerButtonState>(id)) .data_mut(|data| data.get_persisted::<DatePickerButtonState>(id))
.unwrap_or_default(); .unwrap_or_default();
@ -140,7 +148,7 @@ impl<'a> Widget for DatePickerButton<'a> {
let InnerResponse { let InnerResponse {
inner: saved, inner: saved,
response: area_response, response: area_response,
} = Area::new(ui.make_persistent_id(self.id_source)) } = Area::new(ui.make_persistent_id(self.id_salt))
.kind(egui::UiKind::Picker) .kind(egui::UiKind::Picker)
.order(Order::Foreground) .order(Order::Foreground)
.fixed_pos(pos) .fixed_pos(pos)

View File

@ -81,7 +81,7 @@ impl<'a> DatePickerPopup<'a> {
strip.strip(|builder| { strip.strip(|builder| {
builder.sizes(Size::remainder(), 3).horizontal(|mut strip| { builder.sizes(Size::remainder(), 3).horizontal(|mut strip| {
strip.cell(|ui| { strip.cell(|ui| {
ComboBox::from_id_source("date_picker_year") ComboBox::from_id_salt("date_picker_year")
.selected_text(popup_state.year.to_string()) .selected_text(popup_state.year.to_string())
.show_ui(ui, |ui| { .show_ui(ui, |ui| {
for year in today.year() - 100..today.year() + 10 { for year in today.year() - 100..today.year() + 10 {
@ -105,7 +105,7 @@ impl<'a> DatePickerPopup<'a> {
}); });
}); });
strip.cell(|ui| { strip.cell(|ui| {
ComboBox::from_id_source("date_picker_month") ComboBox::from_id_salt("date_picker_month")
.selected_text(month_name(popup_state.month)) .selected_text(month_name(popup_state.month))
.show_ui(ui, |ui| { .show_ui(ui, |ui| {
for month in 1..=12 { for month in 1..=12 {
@ -129,7 +129,7 @@ impl<'a> DatePickerPopup<'a> {
}); });
}); });
strip.cell(|ui| { strip.cell(|ui| {
ComboBox::from_id_source("date_picker_day") ComboBox::from_id_salt("date_picker_day")
.selected_text(popup_state.day.to_string()) .selected_text(popup_state.day.to_string())
.show_ui(ui, |ui| { .show_ui(ui, |ui| {
for day in 1..=popup_state.last_day_of_month() { for day in 1..=popup_state.last_day_of_month() {

View File

@ -116,7 +116,7 @@ impl<'l> StripLayout<'l> {
flags: StripLayoutFlags, flags: StripLayoutFlags,
width: CellSize, width: CellSize,
height: CellSize, height: CellSize,
child_ui_id_source: Id, child_ui_id_salt: Id,
add_cell_contents: impl FnOnce(&mut Ui), add_cell_contents: impl FnOnce(&mut Ui),
) -> (Rect, Response) { ) -> (Rect, Response) {
let max_rect = self.cell_rect(&width, &height); let max_rect = self.cell_rect(&width, &height);
@ -149,7 +149,7 @@ impl<'l> StripLayout<'l> {
); );
} }
let child_ui = self.cell(flags, max_rect, child_ui_id_source, add_cell_contents); let child_ui = self.cell(flags, max_rect, child_ui_id_salt, add_cell_contents);
let used_rect = child_ui.min_rect(); let used_rect = child_ui.min_rect();
@ -197,11 +197,11 @@ impl<'l> StripLayout<'l> {
&mut self, &mut self,
flags: StripLayoutFlags, flags: StripLayoutFlags,
max_rect: Rect, max_rect: Rect,
child_ui_id_source: egui::Id, child_ui_id_salt: egui::Id,
add_cell_contents: impl FnOnce(&mut Ui), add_cell_contents: impl FnOnce(&mut Ui),
) -> Ui { ) -> Ui {
let mut ui_builder = UiBuilder::new() let mut ui_builder = UiBuilder::new()
.id_source(child_ui_id_source) .id_salt(child_ui_id_salt)
.ui_stack_info(egui::UiStackInfo::new(egui::UiKind::TableCell)) .ui_stack_info(egui::UiStackInfo::new(egui::UiKind::TableCell))
.max_rect(max_rect) .max_rect(max_rect)
.layout(self.cell_layout); .layout(self.cell_layout);

View File

@ -213,7 +213,7 @@ impl Default for TableScrollOptions {
/// You must pre-allocate all columns with [`Self::column`]/[`Self::columns`]. /// You must pre-allocate all columns with [`Self::column`]/[`Self::columns`].
/// ///
/// If you have multiple [`Table`]:s in the same [`Ui`] /// If you have multiple [`Table`]:s in the same [`Ui`]
/// you will need to give them unique id:s by with [`Self::id_source`]. /// you will need to give them unique id:s by with [`Self::id_salt`].
/// ///
/// ### Example /// ### Example
/// ``` /// ```
@ -244,7 +244,7 @@ impl Default for TableScrollOptions {
/// ``` /// ```
pub struct TableBuilder<'a> { pub struct TableBuilder<'a> {
ui: &'a mut Ui, ui: &'a mut Ui,
id_source: Id, id_salt: Id,
columns: Vec<Column>, columns: Vec<Column>,
striped: Option<bool>, striped: Option<bool>,
resizable: bool, resizable: bool,
@ -258,7 +258,7 @@ impl<'a> TableBuilder<'a> {
let cell_layout = *ui.layout(); let cell_layout = *ui.layout();
Self { Self {
ui, ui,
id_source: Id::new("__table_state"), id_salt: Id::new("__table_state"),
columns: Default::default(), columns: Default::default(),
striped: None, striped: None,
resizable: false, resizable: false,
@ -272,8 +272,17 @@ impl<'a> TableBuilder<'a> {
/// ///
/// This is required if you have multiple tables in the same [`Ui`]. /// This is required if you have multiple tables in the same [`Ui`].
#[inline] #[inline]
pub fn id_source(mut self, id_source: impl std::hash::Hash) -> Self { #[deprecated = "Renamed id_salt"]
self.id_source = Id::new(id_source); pub fn id_source(self, id_salt: impl std::hash::Hash) -> Self {
self.id_salt(id_salt)
}
/// Give this table a unique id within the parent [`Ui`].
///
/// This is required if you have multiple tables in the same [`Ui`].
#[inline]
pub fn id_salt(mut self, id_salt: impl std::hash::Hash) -> Self {
self.id_salt = Id::new(id_salt);
self self
} }
@ -431,7 +440,7 @@ impl<'a> TableBuilder<'a> {
/// Reset all column widths. /// Reset all column widths.
pub fn reset(&mut self) { pub fn reset(&mut self) {
let state_id = self.ui.id().with(self.id_source); let state_id = self.ui.id().with(self.id_salt);
TableState::reset(self.ui, state_id); TableState::reset(self.ui, state_id);
} }
@ -441,7 +450,7 @@ impl<'a> TableBuilder<'a> {
let Self { let Self {
ui, ui,
id_source, id_salt,
columns, columns,
striped, striped,
resizable, resizable,
@ -452,7 +461,7 @@ impl<'a> TableBuilder<'a> {
let striped = striped.unwrap_or(ui.visuals().striped); let striped = striped.unwrap_or(ui.visuals().striped);
let state_id = ui.id().with(id_source); let state_id = ui.id().with(id_salt);
let (is_sizing_pass, state) = let (is_sizing_pass, state) =
TableState::load(ui, state_id, resizable, &columns, available_width); TableState::load(ui, state_id, resizable, &columns, available_width);
@ -509,7 +518,7 @@ impl<'a> TableBuilder<'a> {
let Self { let Self {
ui, ui,
id_source, id_salt,
columns, columns,
striped, striped,
resizable, resizable,
@ -520,7 +529,7 @@ impl<'a> TableBuilder<'a> {
let striped = striped.unwrap_or(ui.visuals().striped); let striped = striped.unwrap_or(ui.visuals().striped);
let state_id = ui.id().with(id_source); let state_id = ui.id().with(id_salt);
let (is_sizing_pass, state) = let (is_sizing_pass, state) =
TableState::load(ui, state_id, resizable, &columns, available_width); TableState::load(ui, state_id, resizable, &columns, available_width);

View File

@ -91,7 +91,7 @@ fn main() -> eframe::Result {
|i| alternatives[i], |i| alternatives[i],
); );
egui::ComboBox::from_id_source("combo") egui::ComboBox::from_id_salt("combo")
.selected_text("ComboBox") .selected_text("ComboBox")
.width(100.0) .width(100.0)
.show_ui(ui, |ui| { .show_ui(ui, |ui| {

View File

@ -115,7 +115,7 @@ impl eframe::App for MyApp {
// combobox test // combobox test
ui.add_space(20.0); ui.add_space(20.0);
egui::ComboBox::from_id_source("combo_box") egui::ComboBox::from_id_salt("combo_box")
.selected_text("click me") .selected_text("click me")
.show_ui(ui, |ui| { .show_ui(ui, |ui| {
full_span_widget(ui, true); full_span_widget(ui, true);