Compare commits
1 commit
master
...
strong-ids
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2c76949b9b |
5 changed files with 103 additions and 54 deletions
|
@ -32,7 +32,7 @@ impl State {
|
||||||
/// This forms the base of the `Window` container.
|
/// This forms the base of the `Window` container.
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct Area {
|
pub struct Area {
|
||||||
id: Id,
|
strong_id: StrongId,
|
||||||
movable: bool,
|
movable: bool,
|
||||||
interactable: bool,
|
interactable: bool,
|
||||||
order: Order,
|
order: Order,
|
||||||
|
@ -41,9 +41,9 @@ pub struct Area {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Area {
|
impl Area {
|
||||||
pub fn new(id_source: impl Hash) -> Self {
|
pub fn new(strong_id_source: impl Hash) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id: Id::new(id_source),
|
strong_id: StrongId::new(strong_id_source),
|
||||||
movable: true,
|
movable: true,
|
||||||
interactable: true,
|
interactable: true,
|
||||||
order: Order::Middle,
|
order: Order::Middle,
|
||||||
|
@ -53,7 +53,7 @@ impl Area {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn layer(&self) -> LayerId {
|
pub fn layer(&self) -> LayerId {
|
||||||
LayerId::new(self.order, self.id)
|
LayerId::new(self.order, self.strong_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// moveable by dragging the area?
|
/// moveable by dragging the area?
|
||||||
|
@ -105,7 +105,7 @@ pub(crate) struct Prepared {
|
||||||
impl Area {
|
impl Area {
|
||||||
pub(crate) fn begin(self, ctx: &Arc<Context>) -> Prepared {
|
pub(crate) fn begin(self, ctx: &Arc<Context>) -> Prepared {
|
||||||
let Area {
|
let Area {
|
||||||
id,
|
strong_id,
|
||||||
movable,
|
movable,
|
||||||
order,
|
order,
|
||||||
interactable,
|
interactable,
|
||||||
|
@ -113,9 +113,9 @@ impl Area {
|
||||||
fixed_pos,
|
fixed_pos,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let layer_id = LayerId::new(order, id);
|
let layer_id = LayerId::new(order, strong_id);
|
||||||
|
|
||||||
let state = ctx.memory().areas.get(id).cloned();
|
let state = ctx.memory().areas.get(strong_id).cloned();
|
||||||
let mut state = state.unwrap_or_else(|| State {
|
let mut state = state.unwrap_or_else(|| State {
|
||||||
pos: default_pos.unwrap_or_else(|| automatic_area_position(ctx)),
|
pos: default_pos.unwrap_or_else(|| automatic_area_position(ctx)),
|
||||||
size: Vec2::zero(),
|
size: Vec2::zero(),
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
//! the only places where you can put you widgets.
|
//! the only places where you can put you widgets.
|
||||||
|
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
use std::hash::Hash;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -11,14 +12,17 @@ use std::sync::Arc;
|
||||||
///
|
///
|
||||||
/// Panels should be added before adding any `Window`s.
|
/// Panels should be added before adding any `Window`s.
|
||||||
pub struct SidePanel {
|
pub struct SidePanel {
|
||||||
id: Id,
|
strong_id: Id,
|
||||||
max_width: f32,
|
max_width: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SidePanel {
|
impl SidePanel {
|
||||||
/// The given `max_width` is a soft maximum (as always), and the actual panel may be smaller or larger.
|
/// The given `max_width` is a soft maximum (as always), and the actual panel may be smaller or larger.
|
||||||
pub fn left(id: Id, max_width: f32) -> Self {
|
pub fn left(strong_id_source: impl Hash, max_width: f32) -> Self {
|
||||||
Self { id, max_width }
|
Self {
|
||||||
|
strong_id: StrongId::new(strong_id_source),
|
||||||
|
max_width,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +32,10 @@ impl SidePanel {
|
||||||
ctx: &Arc<Context>,
|
ctx: &Arc<Context>,
|
||||||
add_contents: impl FnOnce(&mut Ui) -> R,
|
add_contents: impl FnOnce(&mut Ui) -> R,
|
||||||
) -> (R, Response) {
|
) -> (R, Response) {
|
||||||
let Self { id, max_width } = self;
|
let Self {
|
||||||
|
strong_id,
|
||||||
|
max_width,
|
||||||
|
} = self;
|
||||||
|
|
||||||
let mut panel_rect = ctx.available_rect();
|
let mut panel_rect = ctx.available_rect();
|
||||||
panel_rect.max.x = panel_rect.max.x.at_most(panel_rect.min.x + max_width);
|
panel_rect.max.x = panel_rect.max.x.at_most(panel_rect.min.x + max_width);
|
||||||
|
@ -36,7 +43,7 @@ impl SidePanel {
|
||||||
let layer_id = LayerId::background();
|
let layer_id = LayerId::background();
|
||||||
|
|
||||||
let clip_rect = ctx.input().screen_rect();
|
let clip_rect = ctx.input().screen_rect();
|
||||||
let mut panel_ui = Ui::new(ctx.clone(), layer_id, id, panel_rect, clip_rect);
|
let mut panel_ui = Ui::new(ctx.clone(), layer_id, strong_id, panel_rect, clip_rect);
|
||||||
|
|
||||||
let frame = Frame::panel(&ctx.style());
|
let frame = Frame::panel(&ctx.style());
|
||||||
let r = frame.show(&mut panel_ui, |ui| {
|
let r = frame.show(&mut panel_ui, |ui| {
|
||||||
|
@ -59,16 +66,16 @@ impl SidePanel {
|
||||||
///
|
///
|
||||||
/// Panels should be added before adding any `Window`s.
|
/// Panels should be added before adding any `Window`s.
|
||||||
pub struct TopPanel {
|
pub struct TopPanel {
|
||||||
id: Id,
|
strong_id: StrongId,
|
||||||
max_height: Option<f32>,
|
max_height: Option<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TopPanel {
|
impl TopPanel {
|
||||||
/// Default height is that of `interact_size.y` (i.e. a button),
|
/// Default height is that of `interact_size.y` (i.e. a button),
|
||||||
/// but the panel will expand as needed.
|
/// but the panel will expand as needed.
|
||||||
pub fn top(id: Id) -> Self {
|
pub fn top(strong_id_source: impl Hash) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id,
|
strong_id: StrongId::new(strong_id_source),
|
||||||
max_height: None,
|
max_height: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,7 +87,10 @@ impl TopPanel {
|
||||||
ctx: &Arc<Context>,
|
ctx: &Arc<Context>,
|
||||||
add_contents: impl FnOnce(&mut Ui) -> R,
|
add_contents: impl FnOnce(&mut Ui) -> R,
|
||||||
) -> (R, Response) {
|
) -> (R, Response) {
|
||||||
let Self { id, max_height } = self;
|
let Self {
|
||||||
|
strong_id,
|
||||||
|
max_height,
|
||||||
|
} = self;
|
||||||
let max_height = max_height.unwrap_or_else(|| ctx.style().spacing.interact_size.y);
|
let max_height = max_height.unwrap_or_else(|| ctx.style().spacing.interact_size.y);
|
||||||
|
|
||||||
let mut panel_rect = ctx.available_rect();
|
let mut panel_rect = ctx.available_rect();
|
||||||
|
@ -89,7 +99,7 @@ impl TopPanel {
|
||||||
let layer_id = LayerId::background();
|
let layer_id = LayerId::background();
|
||||||
|
|
||||||
let clip_rect = ctx.input().screen_rect();
|
let clip_rect = ctx.input().screen_rect();
|
||||||
let mut panel_ui = Ui::new(ctx.clone(), layer_id, id, panel_rect, clip_rect);
|
let mut panel_ui = Ui::new(ctx.clone(), layer_id, strong_id, panel_rect, clip_rect);
|
||||||
|
|
||||||
let frame = Frame::panel(&ctx.style());
|
let frame = Frame::panel(&ctx.style());
|
||||||
let r = frame.show(&mut panel_ui, |ui| {
|
let r = frame.show(&mut panel_ui, |ui| {
|
||||||
|
@ -127,10 +137,10 @@ impl CentralPanel {
|
||||||
let panel_rect = ctx.available_rect();
|
let panel_rect = ctx.available_rect();
|
||||||
|
|
||||||
let layer_id = LayerId::background();
|
let layer_id = LayerId::background();
|
||||||
let id = Id::new("central_panel");
|
let strong_id = Id::new("central_panel");
|
||||||
|
|
||||||
let clip_rect = ctx.input().screen_rect();
|
let clip_rect = ctx.input().screen_rect();
|
||||||
let mut panel_ui = Ui::new(ctx.clone(), layer_id, id, panel_rect, clip_rect);
|
let mut panel_ui = Ui::new(ctx.clone(), layer_id, strong_id, panel_rect, clip_rect);
|
||||||
|
|
||||||
let frame = Frame::background(&ctx.style());
|
let frame = Frame::background(&ctx.style());
|
||||||
let r = frame.show(&mut panel_ui, |ui| add_contents(ui));
|
let r = frame.show(&mut panel_ui, |ui| add_contents(ui));
|
||||||
|
|
|
@ -40,14 +40,14 @@ impl Id {
|
||||||
Self(1)
|
Self(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(source: impl Hash) -> Id {
|
pub fn new(source: impl Hash) -> Self {
|
||||||
use std::hash::Hasher;
|
use std::hash::Hasher;
|
||||||
let mut hasher = ahash::AHasher::default();
|
let mut hasher = ahash::AHasher::default();
|
||||||
source.hash(&mut hasher);
|
source.hash(&mut hasher);
|
||||||
Id(hasher.finish())
|
Id(hasher.finish())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with(self, child: impl Hash) -> Id {
|
pub fn with(self, child: impl Hash) -> Self {
|
||||||
use std::hash::Hasher;
|
use std::hash::Hasher;
|
||||||
let mut hasher = ahash::AHasher::default();
|
let mut hasher = ahash::AHasher::default();
|
||||||
hasher.write_u64(self.0);
|
hasher.write_u64(self.0);
|
||||||
|
@ -59,3 +59,49 @@ impl Id {
|
||||||
format!("{:04X}", self.0 as u16)
|
format!("{:04X}", self.0 as u16)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// This is an identifier that must be unique over long time.
|
||||||
|
/// Used for storing state, like window position, scroll amount, etc.
|
||||||
|
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
|
pub struct StrongId(u64);
|
||||||
|
|
||||||
|
impl StrongId {
|
||||||
|
pub fn background() -> Self {
|
||||||
|
Self(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tooltip() -> Self {
|
||||||
|
Self(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(source: impl Hash) -> Self {
|
||||||
|
use std::hash::Hasher;
|
||||||
|
let mut hasher = ahash::AHasher::default();
|
||||||
|
source.hash(&mut hasher);
|
||||||
|
Id(hasher.finish())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with(self, child: impl Hash) -> Self {
|
||||||
|
use std::hash::Hasher;
|
||||||
|
let mut hasher = ahash::AHasher::default();
|
||||||
|
hasher.write_u64(self.0);
|
||||||
|
child.hash(&mut hasher);
|
||||||
|
Id(hasher.finish())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn short_debug_format(&self) -> String {
|
||||||
|
format!("{:04X}", self.0 as u16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Ok to weaken a `StrongId`
|
||||||
|
impl From<StrongId> for Id {
|
||||||
|
fn from(strong: StrongId) -> Self {
|
||||||
|
Id(strong.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,14 +1,6 @@
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
use crate::{
|
use crate::{cache::Cache, color::Hsva, *};
|
||||||
area,
|
|
||||||
cache::Cache,
|
|
||||||
collapsing_header, menu,
|
|
||||||
paint::color::{Hsva, Srgba},
|
|
||||||
resize, scroll_area,
|
|
||||||
widgets::text_edit,
|
|
||||||
window, Id, LayerId, Pos2, Rect,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// The data that Egui persists between frames.
|
/// The data that Egui persists between frames.
|
||||||
///
|
///
|
||||||
|
@ -24,11 +16,11 @@ pub struct Memory {
|
||||||
pub(crate) interaction: Interaction,
|
pub(crate) interaction: Interaction,
|
||||||
|
|
||||||
// states of various types of widgets
|
// states of various types of widgets
|
||||||
pub(crate) collapsing_headers: HashMap<Id, collapsing_header::State>,
|
pub(crate) collapsing_headers: HashMap<StrongId, collapsing_header::State>,
|
||||||
#[cfg_attr(feature = "serde", serde(skip))]
|
#[cfg_attr(feature = "serde", serde(skip))]
|
||||||
pub(crate) menu_bar: HashMap<Id, menu::BarState>,
|
pub(crate) menu_bar: HashMap<StrongId, menu::BarState>,
|
||||||
pub(crate) resize: HashMap<Id, resize::State>,
|
pub(crate) resize: HashMap<StrongId, resize::State>,
|
||||||
pub(crate) scroll_areas: HashMap<Id, scroll_area::State>,
|
pub(crate) scroll_areas: HashMap<StrongId, scroll_area::State>,
|
||||||
pub(crate) text_edit: HashMap<Id, text_edit::State>,
|
pub(crate) text_edit: HashMap<Id, text_edit::State>,
|
||||||
|
|
||||||
#[cfg_attr(feature = "serde", serde(skip))]
|
#[cfg_attr(feature = "serde", serde(skip))]
|
||||||
|
@ -197,7 +189,7 @@ impl Memory {
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
#[cfg_attr(feature = "serde", serde(default))]
|
#[cfg_attr(feature = "serde", serde(default))]
|
||||||
pub struct Areas {
|
pub struct Areas {
|
||||||
areas: HashMap<Id, area::State>,
|
areas: HashMap<StrongId, area::State>,
|
||||||
/// Top is last
|
/// Top is last
|
||||||
order: Vec<LayerId>,
|
order: Vec<LayerId>,
|
||||||
visible_last_frame: HashSet<LayerId>,
|
visible_last_frame: HashSet<LayerId>,
|
||||||
|
|
|
@ -7,12 +7,11 @@ use crate::{color::*, containers::*, layout::*, mutex::MutexGuard, paint::*, wid
|
||||||
/// Represents a region of the screen
|
/// Represents a region of the screen
|
||||||
/// with a type of layout (horizontal or vertical).
|
/// with a type of layout (horizontal or vertical).
|
||||||
pub struct Ui {
|
pub struct Ui {
|
||||||
/// ID of this ui.
|
/// Used to seed more StrongId:s.
|
||||||
/// Generated based on id of parent ui together with
|
strong_id: StrongId,
|
||||||
/// another source of child identity (e.g. window title).
|
|
||||||
/// Acts like a namespace for child uis.
|
/// For automatic Id generation.
|
||||||
/// Hopefully unique.
|
auto_id: Id,
|
||||||
id: Id,
|
|
||||||
|
|
||||||
painter: Painter,
|
painter: Painter,
|
||||||
|
|
||||||
|
@ -49,11 +48,6 @@ pub struct Ui {
|
||||||
/// If something has already been added, this will point ot style.spacing.item_spacing beyond the latest child.
|
/// If something has already been added, this will point ot style.spacing.item_spacing beyond the latest child.
|
||||||
/// The cursor can thus be style.spacing.item_spacing pixels outside of the min_rect.
|
/// The cursor can thus be style.spacing.item_spacing pixels outside of the min_rect.
|
||||||
cursor: Pos2, // TODO: move into Layout?
|
cursor: Pos2, // TODO: move into Layout?
|
||||||
|
|
||||||
/// How many children has been added to us?
|
|
||||||
/// This is only used to create a unique interact ID for some widgets
|
|
||||||
/// that work as long as no other widgets are added/removed while interacting.
|
|
||||||
child_count: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ui {
|
impl Ui {
|
||||||
|
@ -63,7 +57,7 @@ impl Ui {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
ctx: Arc<Context>,
|
ctx: Arc<Context>,
|
||||||
layer_id: LayerId,
|
layer_id: LayerId,
|
||||||
id: Id,
|
strong_id: StrongId,
|
||||||
max_rect: Rect,
|
max_rect: Rect,
|
||||||
clip_rect: Rect,
|
clip_rect: Rect,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -73,14 +67,14 @@ impl Ui {
|
||||||
let min_size = Vec2::zero(); // TODO: From Style
|
let min_size = Vec2::zero(); // TODO: From Style
|
||||||
let min_rect = layout.rect_from_cursor_size(cursor, min_size);
|
let min_rect = layout.rect_from_cursor_size(cursor, min_size);
|
||||||
Ui {
|
Ui {
|
||||||
id,
|
strong_id,
|
||||||
|
auto_id: strong_id.with("auto"),
|
||||||
painter: Painter::new(ctx, layer_id, clip_rect),
|
painter: Painter::new(ctx, layer_id, clip_rect),
|
||||||
min_rect,
|
min_rect,
|
||||||
max_rect,
|
max_rect,
|
||||||
style,
|
style,
|
||||||
layout,
|
layout,
|
||||||
cursor,
|
cursor,
|
||||||
child_count: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,7 +360,7 @@ 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_source: IdSource) -> StrongId
|
||||||
where
|
where
|
||||||
IdSource: Hash + std::fmt::Debug,
|
IdSource: Hash + std::fmt::Debug,
|
||||||
{
|
{
|
||||||
|
@ -379,15 +373,22 @@ impl Ui {
|
||||||
/// Call AFTER allocating new space for your widget.
|
/// Call AFTER allocating new space for your widget.
|
||||||
// TODO: return from `allocate_space` ?
|
// TODO: return from `allocate_space` ?
|
||||||
pub fn make_position_id(&self) -> Id {
|
pub fn make_position_id(&self) -> Id {
|
||||||
self.id.with(self.child_count)
|
let id = self.id.with(self.child_count);
|
||||||
|
// self.ctx().register_unique_id(id, self.cursor, "position"); // NO: position may change until we interact
|
||||||
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Interaction
|
/// # Interaction
|
||||||
impl Ui {
|
impl Ui {
|
||||||
pub fn interact(&self, rect: Rect, id: Id, sense: Sense) -> Response {
|
pub fn interact(&self, rect: Rect, id: impl Into<Id>, sense: Sense) -> Response {
|
||||||
self.ctx()
|
self.ctx().interact(
|
||||||
.interact(self.layer_id(), self.clip_rect(), rect, Some(id), sense)
|
self.layer_id(),
|
||||||
|
self.clip_rect(),
|
||||||
|
rect,
|
||||||
|
Some(id.into()),
|
||||||
|
sense,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interact_hover(&self, rect: Rect) -> Response {
|
pub fn interact_hover(&self, rect: Rect) -> Response {
|
||||||
|
|
Loading…
Reference in a new issue