Make `Area` state public (#4576)
This commit is contained in:
parent
913cef3361
commit
c7cb524bdb
|
|
@ -4,25 +4,34 @@
|
||||||
|
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
/// State that is persisted between frames.
|
/// State of an [`Area`] that is persisted between frames.
|
||||||
// TODO(emilk): this is not currently stored in `Memory::data`, but maybe it should be?
|
///
|
||||||
|
/// Areas back [`crate::Window`]s and other floating containers,
|
||||||
|
/// like tooltips and the popups of [`crate::ComboBox`].
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
pub(crate) struct State {
|
pub struct AreaState {
|
||||||
/// Last known pos of the pivot
|
/// Last known position of the pivot.
|
||||||
pub pivot_pos: Pos2,
|
pub pivot_pos: Pos2,
|
||||||
|
|
||||||
|
/// The anchor point of the area, i.e. where on the area the [`Self::pivot_pos`] refers to.
|
||||||
pub pivot: Align2,
|
pub pivot: Align2,
|
||||||
|
|
||||||
/// Last know size. Used for catching clicks.
|
/// Last known size.
|
||||||
pub size: Vec2,
|
pub size: Vec2,
|
||||||
|
|
||||||
/// If false, clicks goes straight through to what is behind us.
|
/// If false, clicks goes straight through to what is behind us. Useful for tooltips etc.
|
||||||
/// Good for tooltips etc.
|
|
||||||
pub interactable: bool,
|
pub interactable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl AreaState {
|
||||||
|
/// Load the state of an [`Area`] from memory.
|
||||||
|
pub fn load(ctx: &Context, id: Id) -> Option<Self> {
|
||||||
|
// TODO(emilk): Area state is not currently stored in `Memory::data`, but maybe it should be?
|
||||||
|
ctx.memory(|mem| mem.areas().get(id).copied())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The left top positions of the area.
|
||||||
pub fn left_top_pos(&self) -> Pos2 {
|
pub fn left_top_pos(&self) -> Pos2 {
|
||||||
pos2(
|
pos2(
|
||||||
self.pivot_pos.x - self.pivot.x().to_factor() * self.size.x,
|
self.pivot_pos.x - self.pivot.x().to_factor() * self.size.x,
|
||||||
|
|
@ -30,6 +39,7 @@ impl State {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Move the left top positions of the area.
|
||||||
pub fn set_left_top_pos(&mut self, pos: Pos2) {
|
pub fn set_left_top_pos(&mut self, pos: Pos2) {
|
||||||
self.pivot_pos = pos2(
|
self.pivot_pos = pos2(
|
||||||
pos.x + self.pivot.x().to_factor() * self.size.x,
|
pos.x + self.pivot.x().to_factor() * self.size.x,
|
||||||
|
|
@ -37,6 +47,7 @@ impl State {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Where the area is on screen.
|
||||||
pub fn rect(&self) -> Rect {
|
pub fn rect(&self) -> Rect {
|
||||||
Rect::from_min_size(self.left_top_pos(), self.size)
|
Rect::from_min_size(self.left_top_pos(), self.size)
|
||||||
}
|
}
|
||||||
|
|
@ -75,6 +86,10 @@ pub struct Area {
|
||||||
new_pos: Option<Pos2>,
|
new_pos: Option<Pos2>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl WidgetWithState for Area {
|
||||||
|
type State = AreaState;
|
||||||
|
}
|
||||||
|
|
||||||
impl Area {
|
impl Area {
|
||||||
/// The `id` must be globally unique.
|
/// The `id` must be globally unique.
|
||||||
pub fn new(id: Id) -> Self {
|
pub fn new(id: Id) -> Self {
|
||||||
|
|
@ -267,7 +282,7 @@ impl Area {
|
||||||
|
|
||||||
pub(crate) struct Prepared {
|
pub(crate) struct Prepared {
|
||||||
layer_id: LayerId,
|
layer_id: LayerId,
|
||||||
state: State,
|
state: AreaState,
|
||||||
move_response: Response,
|
move_response: Response,
|
||||||
enabled: bool,
|
enabled: bool,
|
||||||
constrain: bool,
|
constrain: bool,
|
||||||
|
|
@ -313,13 +328,11 @@ impl Area {
|
||||||
|
|
||||||
let layer_id = LayerId::new(order, id);
|
let layer_id = LayerId::new(order, id);
|
||||||
|
|
||||||
let state = ctx
|
let state = AreaState::load(ctx, id).map(|mut state| {
|
||||||
.memory(|mem| mem.areas().get(id).copied())
|
// override the saved state with the correct value
|
||||||
.map(|mut state| {
|
state.pivot = pivot;
|
||||||
// override the saved state with the correct value
|
state
|
||||||
state.pivot = pivot;
|
});
|
||||||
state
|
|
||||||
});
|
|
||||||
let is_new = state.is_none();
|
let is_new = state.is_none();
|
||||||
if is_new {
|
if is_new {
|
||||||
ctx.request_repaint(); // if we don't know the previous size we are likely drawing the area in the wrong place
|
ctx.request_repaint(); // if we don't know the previous size we are likely drawing the area in the wrong place
|
||||||
|
|
@ -341,7 +354,7 @@ impl Area {
|
||||||
size = size.at_most(constrain_rect.size());
|
size = size.at_most(constrain_rect.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
State {
|
AreaState {
|
||||||
pivot_pos: default_pos.unwrap_or_else(|| automatic_area_position(ctx)),
|
pivot_pos: default_pos.unwrap_or_else(|| automatic_area_position(ctx)),
|
||||||
pivot,
|
pivot,
|
||||||
size,
|
size,
|
||||||
|
|
@ -433,7 +446,7 @@ impl Area {
|
||||||
}
|
}
|
||||||
|
|
||||||
let layer_id = LayerId::new(self.order, self.id);
|
let layer_id = LayerId::new(self.order, self.id);
|
||||||
let area_rect = ctx.memory(|mem| mem.areas().get(self.id).map(|area| area.rect()));
|
let area_rect = AreaState::load(ctx, self.id).map(|state| state.rect());
|
||||||
if let Some(area_rect) = area_rect {
|
if let Some(area_rect) = area_rect {
|
||||||
let clip_rect = Rect::EVERYTHING;
|
let clip_rect = Rect::EVERYTHING;
|
||||||
let painter = Painter::new(ctx.clone(), layer_id, clip_rect);
|
let painter = Painter::new(ctx.clone(), layer_id, clip_rect);
|
||||||
|
|
@ -449,11 +462,11 @@ impl Area {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Prepared {
|
impl Prepared {
|
||||||
pub(crate) fn state(&self) -> &State {
|
pub(crate) fn state(&self) -> &AreaState {
|
||||||
&self.state
|
&self.state
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn state_mut(&mut self) -> &mut State {
|
pub(crate) fn state_mut(&mut self) -> &mut AreaState {
|
||||||
&mut self.state
|
&mut self.state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -542,7 +555,7 @@ fn automatic_area_position(ctx: &Context) -> Pos2 {
|
||||||
mem.areas()
|
mem.areas()
|
||||||
.visible_windows()
|
.visible_windows()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(State::rect)
|
.map(AreaState::rect)
|
||||||
.collect()
|
.collect()
|
||||||
});
|
});
|
||||||
existing.sort_by_key(|r| r.left().round() as i32);
|
existing.sort_by_key(|r| r.left().round() as i32);
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ pub mod scroll_area;
|
||||||
pub(crate) mod window;
|
pub(crate) mod window;
|
||||||
|
|
||||||
pub use {
|
pub use {
|
||||||
area::Area,
|
area::{Area, AreaState},
|
||||||
collapsing_header::{CollapsingHeader, CollapsingResponse},
|
collapsing_header::{CollapsingHeader, CollapsingResponse},
|
||||||
combo_box::*,
|
combo_box::*,
|
||||||
frame::Frame,
|
frame::Frame,
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
use std::{borrow::Cow, cell::RefCell, panic::Location, sync::Arc, time::Duration};
|
use std::{borrow::Cow, cell::RefCell, panic::Location, sync::Arc, time::Duration};
|
||||||
|
|
||||||
|
use containers::area::AreaState;
|
||||||
use epaint::{
|
use epaint::{
|
||||||
emath::TSTransform, mutex::*, stats::*, text::Fonts, util::OrderedFloat, TessellationOptions, *,
|
emath::TSTransform, mutex::*, stats::*, text::Fonts, util::OrderedFloat, TessellationOptions, *,
|
||||||
};
|
};
|
||||||
|
|
@ -490,7 +491,7 @@ impl ContextImpl {
|
||||||
// Ensure we register the background area so panels and background ui can catch clicks:
|
// Ensure we register the background area so panels and background ui can catch clicks:
|
||||||
self.memory.areas_mut().set_state(
|
self.memory.areas_mut().set_state(
|
||||||
LayerId::background(),
|
LayerId::background(),
|
||||||
containers::area::State {
|
AreaState {
|
||||||
pivot_pos: screen_rect.left_top(),
|
pivot_pos: screen_rect.left_top(),
|
||||||
pivot: Align2::LEFT_TOP,
|
pivot: Align2::LEFT_TOP,
|
||||||
size: screen_rect.size(),
|
size: screen_rect.size(),
|
||||||
|
|
@ -2702,7 +2703,7 @@ impl Context {
|
||||||
ui.label("Hover to highlight");
|
ui.label("Hover to highlight");
|
||||||
let layers_ids: Vec<LayerId> = self.memory(|mem| mem.areas().order().to_vec());
|
let layers_ids: Vec<LayerId> = self.memory(|mem| mem.areas().order().to_vec());
|
||||||
for layer_id in layers_ids {
|
for layer_id in layers_ids {
|
||||||
let area = self.memory(|mem| mem.areas().get(layer_id.id).copied());
|
let area = AreaState::load(self, layer_id.id);
|
||||||
if let Some(area) = area {
|
if let Some(area) = area {
|
||||||
let is_visible = self.memory(|mem| mem.areas().is_visible(&layer_id));
|
let is_visible = self.memory(|mem| mem.areas().is_visible(&layer_id));
|
||||||
if !is_visible {
|
if !is_visible {
|
||||||
|
|
|
||||||
|
|
@ -934,7 +934,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: IdMap<area::State>,
|
areas: IdMap<area::AreaState>,
|
||||||
|
|
||||||
/// Back-to-front. Top is last.
|
/// Back-to-front. Top is last.
|
||||||
order: Vec<LayerId>,
|
order: Vec<LayerId>,
|
||||||
|
|
@ -955,7 +955,7 @@ impl Areas {
|
||||||
self.areas.len()
|
self.areas.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get(&self, id: Id) -> Option<&area::State> {
|
pub(crate) fn get(&self, id: Id) -> Option<&area::AreaState> {
|
||||||
self.areas.get(&id)
|
self.areas.get(&id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -973,7 +973,7 @@ impl Areas {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_state(&mut self, layer_id: LayerId, state: area::State) {
|
pub(crate) fn set_state(&mut self, layer_id: LayerId, state: area::AreaState) {
|
||||||
self.visible_current_frame.insert(layer_id);
|
self.visible_current_frame.insert(layer_id);
|
||||||
self.areas.insert(layer_id.id, state);
|
self.areas.insert(layer_id.id, state);
|
||||||
if !self.order.iter().any(|x| *x == layer_id) {
|
if !self.order.iter().any(|x| *x == layer_id) {
|
||||||
|
|
@ -1022,7 +1022,7 @@ impl Areas {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn visible_windows(&self) -> Vec<&area::State> {
|
pub(crate) fn visible_windows(&self) -> Vec<&area::AreaState> {
|
||||||
self.visible_layer_ids()
|
self.visible_layer_ids()
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|layer| layer.order == crate::Order::Middle)
|
.filter(|layer| layer.order == crate::Order::Middle)
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper so that you can do `TextEdit::State::read…`
|
/// Helper so that you can do e.g. `TextEdit::State::load`.
|
||||||
pub trait WidgetWithState {
|
pub trait WidgetWithState {
|
||||||
type State;
|
type State;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue