2023-09-22 14:33:51 +00:00
use crate ::{
2024-01-07 13:14:21 +00:00
seal ::Sealed , AnyElement , AnyModel , AnyWeakModel , AppContext , AvailableSpace , BorrowWindow ,
2024-01-08 18:07:20 +00:00
Bounds , ContentMask , Element , ElementId , Entity , EntityId , Flatten , FocusHandle , FocusableView ,
IntoElement , LayoutId , Model , Pixels , Point , Render , Size , StackingOrder , Style , TextStyle ,
ViewContext , VisualContext , WeakModel , WindowContext ,
2023-10-26 16:17:45 +00:00
} ;
2023-10-26 17:41:42 +00:00
use anyhow ::{ Context , Result } ;
2023-11-01 18:31:23 +00:00
use std ::{
2024-01-08 11:29:54 +00:00
any ::{ type_name , TypeId } ,
2023-12-14 22:15:56 +00:00
fmt ,
2023-11-02 08:41:49 +00:00
hash ::{ Hash , Hasher } ,
2023-11-01 18:31:23 +00:00
} ;
2023-09-22 14:33:51 +00:00
2024-01-17 18:21:29 +00:00
/// A view is a piece of state that can be presented on screen by implementing the [Render] trait.
/// Views implement [Element] and can composed with other views, and every window is created with a root view.
2023-10-30 19:36:48 +00:00
pub struct View < V > {
2024-01-17 18:21:29 +00:00
/// A view is just a [Model] whose type implements `Render`, and the model is accessible via this field.
2023-11-19 03:05:47 +00:00
pub model : Model < V > ,
2023-09-22 14:33:51 +00:00
}
2023-10-31 00:43:07 +00:00
impl < V > Sealed for View < V > { }
2024-01-17 18:21:29 +00:00
#[ doc(hidden) ]
2024-01-08 18:07:20 +00:00
pub struct AnyViewState {
root_style : Style ,
cache_key : Option < ViewCacheKey > ,
element : Option < AnyElement > ,
}
struct ViewCacheKey {
bounds : Bounds < Pixels > ,
stacking_order : StackingOrder ,
content_mask : ContentMask < Pixels > ,
text_style : TextStyle ,
}
2023-10-31 00:43:07 +00:00
impl < V : 'static > Entity < V > for View < V > {
type Weak = WeakView < V > ;
fn entity_id ( & self ) -> EntityId {
self . model . entity_id
}
fn downgrade ( & self ) -> Self ::Weak {
2023-10-26 16:17:45 +00:00
WeakView {
2023-10-30 19:36:48 +00:00
model : self . model . downgrade ( ) ,
2023-10-26 16:17:45 +00:00
}
}
2023-10-31 00:43:07 +00:00
fn upgrade_from ( weak : & Self ::Weak ) -> Option < Self >
where
Self : Sized ,
{
let model = weak . model . upgrade ( ) ? ;
Some ( View { model } )
}
}
impl < V : 'static > View < V > {
/// Convert this strong view reference into a weak view reference.
pub fn downgrade ( & self ) -> WeakView < V > {
Entity ::downgrade ( self )
}
2024-01-19 16:18:50 +00:00
/// Updates the view's state with the given function, which is passed a mutable reference and a context.
2023-10-26 17:41:42 +00:00
pub fn update < C , R > (
2023-10-26 16:17:45 +00:00
& self ,
2023-10-26 17:41:42 +00:00
cx : & mut C ,
2023-11-02 08:41:49 +00:00
f : impl FnOnce ( & mut V , & mut ViewContext < '_ , V > ) -> R ,
2023-10-26 17:41:42 +00:00
) -> C ::Result < R >
where
C : VisualContext ,
{
cx . update_view ( self , f )
2023-10-26 16:17:45 +00:00
}
2023-10-30 22:19:40 +00:00
2024-01-17 18:21:29 +00:00
/// Obtain a read-only reference to this view's state.
2023-10-30 22:19:40 +00:00
pub fn read < ' a > ( & self , cx : & ' a AppContext ) -> & ' a V {
self . model . read ( cx )
}
2023-11-15 17:45:51 +00:00
2024-01-17 18:21:29 +00:00
/// Gets a [FocusHandle] for this view when its state implements [FocusableView].
2023-11-16 00:36:43 +00:00
pub fn focus_handle ( & self , cx : & AppContext ) -> FocusHandle
where
V : FocusableView ,
{
self . read ( cx ) . focus_handle ( cx )
}
2023-10-26 16:17:45 +00:00
}
2023-11-20 19:21:42 +00:00
impl < V : Render > Element for View < V > {
type State = Option < AnyElement > ;
2023-12-31 15:33:40 +00:00
fn request_layout (
2023-11-20 19:21:42 +00:00
& mut self ,
_state : Option < Self ::State > ,
cx : & mut WindowContext ,
) -> ( LayoutId , Self ::State ) {
2024-01-10 14:00:40 +00:00
cx . with_view_id ( self . entity_id ( ) , | cx | {
let mut element = self . update ( cx , | view , cx | view . render ( cx ) . into_any_element ( ) ) ;
let layout_id = element . request_layout ( cx ) ;
( layout_id , Some ( element ) )
} )
2023-11-20 19:21:42 +00:00
}
2023-12-14 22:15:18 +00:00
fn paint ( & mut self , _ : Bounds < Pixels > , element : & mut Self ::State , cx : & mut WindowContext ) {
2024-01-11 11:48:05 +00:00
cx . paint_view ( self . entity_id ( ) , | cx | element . take ( ) . unwrap ( ) . paint ( cx ) ) ;
2023-11-20 19:21:42 +00:00
}
}
2023-10-26 16:17:45 +00:00
impl < V > Clone for View < V > {
fn clone ( & self ) -> Self {
Self {
2023-10-30 19:36:48 +00:00
model : self . model . clone ( ) ,
2023-10-26 16:17:45 +00:00
}
}
}
2024-01-08 11:29:54 +00:00
impl < T > std ::fmt ::Debug for View < T > {
fn fmt ( & self , f : & mut fmt ::Formatter < '_ > ) -> fmt ::Result {
f . debug_struct ( & format! ( " View< {} > " , type_name ::< T > ( ) ) )
. field ( " entity_id " , & self . model . entity_id )
. finish_non_exhaustive ( )
}
}
2023-11-02 08:41:49 +00:00
impl < V > Hash for View < V > {
fn hash < H : Hasher > ( & self , state : & mut H ) {
self . model . hash ( state ) ;
2023-10-12 17:30:00 +00:00
}
}
2023-11-02 08:41:49 +00:00
impl < V > PartialEq for View < V > {
fn eq ( & self , other : & Self ) -> bool {
self . model = = other . model
2023-10-11 17:40:42 +00:00
}
2023-11-02 08:41:49 +00:00
}
2023-10-11 17:40:42 +00:00
2023-11-02 08:41:49 +00:00
impl < V > Eq for View < V > { }
2023-10-18 12:12:50 +00:00
2024-01-17 18:21:29 +00:00
/// A weak variant of [View] which does not prevent the view from being released.
2023-10-26 16:17:45 +00:00
pub struct WeakView < V > {
2023-10-30 19:36:48 +00:00
pub ( crate ) model : WeakModel < V > ,
2023-10-26 16:17:45 +00:00
}
2023-10-26 17:41:42 +00:00
impl < V : 'static > WeakView < V > {
2024-01-17 18:21:29 +00:00
/// Gets the entity id associated with this handle.
2023-11-02 09:53:28 +00:00
pub fn entity_id ( & self ) -> EntityId {
self . model . entity_id
}
2024-01-17 18:21:29 +00:00
/// Obtain a strong handle for the view if it hasn't been released.
2023-10-26 16:17:45 +00:00
pub fn upgrade ( & self ) -> Option < View < V > > {
2023-10-31 00:43:07 +00:00
Entity ::upgrade_from ( self )
2023-09-22 14:33:51 +00:00
}
2023-10-26 17:41:42 +00:00
2024-01-19 16:18:50 +00:00
/// Updates this view's state if it hasn't been released.
2024-01-17 18:21:29 +00:00
/// Returns an error if this view has been released.
2023-11-02 08:41:49 +00:00
pub fn update < C , R > (
2023-10-26 17:41:42 +00:00
& self ,
2023-11-02 08:41:49 +00:00
cx : & mut C ,
f : impl FnOnce ( & mut V , & mut ViewContext < '_ , V > ) -> R ,
) -> Result < R >
where
C : VisualContext ,
Result < C ::Result < R > > : Flatten < R > ,
{
2023-10-26 17:41:42 +00:00
let view = self . upgrade ( ) . context ( " error upgrading view " ) ? ;
2023-11-02 08:41:49 +00:00
Ok ( view . update ( cx , f ) ) . flatten ( )
2023-10-26 17:41:42 +00:00
}
2024-01-05 03:16:25 +00:00
2024-01-17 18:21:29 +00:00
/// Assert that the view referenced by this handle has been released.
2024-01-05 03:16:25 +00:00
#[ cfg(any(test, feature = " test-support " )) ]
2024-01-17 18:21:29 +00:00
pub fn assert_released ( & self ) {
self . model . assert_released ( )
2024-01-05 03:16:25 +00:00
}
2023-10-26 17:41:42 +00:00
}
impl < V > Clone for WeakView < V > {
fn clone ( & self ) -> Self {
Self {
2023-10-30 19:36:48 +00:00
model : self . model . clone ( ) ,
2023-10-26 17:41:42 +00:00
}
}
2023-09-22 14:33:51 +00:00
}
2023-11-02 08:41:49 +00:00
impl < V > Hash for WeakView < V > {
fn hash < H : Hasher > ( & self , state : & mut H ) {
self . model . hash ( state ) ;
2023-10-12 17:30:00 +00:00
}
}
2023-11-02 08:41:49 +00:00
impl < V > PartialEq for WeakView < V > {
fn eq ( & self , other : & Self ) -> bool {
self . model = = other . model
2023-10-18 12:12:50 +00:00
}
2023-09-22 14:33:51 +00:00
}
2023-11-02 08:41:49 +00:00
impl < V > Eq for WeakView < V > { }
2023-09-22 14:33:51 +00:00
2024-01-17 22:58:58 +00:00
/// A dynamically-typed handle to a view, which can be downcast to a [View] for a specific type.
2023-10-31 15:16:30 +00:00
#[ derive(Clone, Debug) ]
pub struct AnyView {
model : AnyModel ,
2024-01-08 18:07:20 +00:00
request_layout : fn ( & AnyView , & mut WindowContext ) -> ( LayoutId , AnyElement ) ,
cache : bool ,
2023-10-31 15:16:30 +00:00
}
2023-09-22 14:33:51 +00:00
2023-10-26 17:41:42 +00:00
impl AnyView {
2024-01-17 18:21:29 +00:00
/// Indicate that this view should be cached when using it as an element.
/// When using this method, the view's previous layout and paint will be recycled from the previous frame if [ViewContext::notify] has not been called since it was rendered.
/// The one exception is when [WindowContext::refresh] is called, in which case caching is ignored.
2024-01-08 18:07:20 +00:00
pub fn cached ( mut self ) -> Self {
self . cache = true ;
self
}
2024-01-17 18:21:29 +00:00
/// Convert this to a weak handle.
2023-10-31 15:19:46 +00:00
pub fn downgrade ( & self ) -> AnyWeakView {
AnyWeakView {
model : self . model . downgrade ( ) ,
2024-01-08 18:07:20 +00:00
layout : self . request_layout ,
2023-10-31 15:19:46 +00:00
}
}
2024-01-17 18:21:29 +00:00
/// Convert this to a [View] of a specific type.
/// If this handle does not contain a view of the specified type, returns itself in an `Err` variant.
2023-10-31 15:16:30 +00:00
pub fn downcast < T : 'static > ( self ) -> Result < View < T > , Self > {
match self . model . downcast ( ) {
Ok ( model ) = > Ok ( View { model } ) ,
Err ( model ) = > Err ( Self {
model ,
2024-01-08 18:07:20 +00:00
request_layout : self . request_layout ,
cache : self . cache ,
2023-10-31 15:16:30 +00:00
} ) ,
}
2023-10-30 22:19:40 +00:00
}
2024-01-17 18:21:29 +00:00
/// Gets the [TypeId] of the underlying view.
2023-11-02 08:41:49 +00:00
pub fn entity_type ( & self ) -> TypeId {
2023-10-31 15:16:30 +00:00
self . model . entity_type
2023-10-30 22:19:40 +00:00
}
2024-01-17 18:21:29 +00:00
/// Gets the entity id of this handle.
2023-11-17 20:23:12 +00:00
pub fn entity_id ( & self ) -> EntityId {
self . model . entity_id ( )
}
2023-11-15 19:41:09 +00:00
pub ( crate ) fn draw (
& self ,
origin : Point < Pixels > ,
available_space : Size < AvailableSpace > ,
cx : & mut WindowContext ,
) {
2024-01-11 11:48:05 +00:00
cx . paint_view ( self . entity_id ( ) , | cx | {
2024-01-10 14:00:40 +00:00
cx . with_absolute_element_offset ( origin , | cx | {
let ( layout_id , mut rendered_element ) = ( self . request_layout ) ( self , cx ) ;
cx . compute_layout ( layout_id , available_space ) ;
rendered_element . paint ( cx )
} ) ;
2023-11-15 19:41:09 +00:00
} )
2023-10-26 17:41:42 +00:00
}
}
2023-10-31 15:16:30 +00:00
impl < V : Render > From < View < V > > for AnyView {
fn from ( value : View < V > ) -> Self {
AnyView {
model : value . model . into_any ( ) ,
2024-01-08 18:07:20 +00:00
request_layout : any_view ::request_layout ::< V > ,
cache : false ,
2023-10-31 15:16:30 +00:00
}
2023-10-12 17:30:00 +00:00
}
}
2023-11-20 02:32:31 +00:00
impl Element for AnyView {
2024-01-08 18:07:20 +00:00
type State = AnyViewState ;
2023-11-19 03:05:47 +00:00
2023-12-31 15:33:40 +00:00
fn request_layout (
2023-11-19 03:05:47 +00:00
& mut self ,
2024-01-08 18:07:20 +00:00
state : Option < Self ::State > ,
2023-11-20 19:21:42 +00:00
cx : & mut WindowContext ,
2023-11-19 03:05:47 +00:00
) -> ( LayoutId , Self ::State ) {
2024-01-10 14:00:40 +00:00
cx . with_view_id ( self . entity_id ( ) , | cx | {
if self . cache {
if let Some ( state ) = state {
let layout_id = cx . request_layout ( & state . root_style , None ) ;
return ( layout_id , state ) ;
}
2024-01-08 18:07:20 +00:00
}
2024-01-10 14:00:40 +00:00
let ( layout_id , element ) = ( self . request_layout ) ( self , cx ) ;
let root_style = cx . layout_style ( layout_id ) . unwrap ( ) . clone ( ) ;
let state = AnyViewState {
root_style ,
cache_key : None ,
element : Some ( element ) ,
} ;
( layout_id , state )
} )
2023-11-19 03:05:47 +00:00
}
2024-01-08 18:07:20 +00:00
fn paint ( & mut self , bounds : Bounds < Pixels > , state : & mut Self ::State , cx : & mut WindowContext ) {
2024-01-11 11:48:05 +00:00
cx . paint_view ( self . entity_id ( ) , | cx | {
2024-01-08 18:31:50 +00:00
if ! self . cache {
state . element . take ( ) . unwrap ( ) . paint ( cx ) ;
return ;
}
2024-01-08 18:07:20 +00:00
2024-01-08 18:31:50 +00:00
if let Some ( cache_key ) = state . cache_key . as_mut ( ) {
if cache_key . bounds = = bounds
& & cache_key . content_mask = = cx . content_mask ( )
& & cache_key . stacking_order = = * cx . stacking_order ( )
& & cache_key . text_style = = cx . text_style ( )
& & ! cx . window . dirty_views . contains ( & self . entity_id ( ) )
2024-01-10 16:27:02 +00:00
& & ! cx . window . refreshing
2024-01-08 18:31:50 +00:00
{
2024-01-10 22:06:10 +00:00
cx . reuse_view ( ) ;
2024-01-09 11:37:24 +00:00
return ;
2024-01-08 18:31:50 +00:00
}
2024-01-08 18:07:20 +00:00
}
2024-01-19 09:26:39 +00:00
if let Some ( mut element ) = state . element . take ( ) {
element . paint ( cx ) ;
} else {
let mut element = ( self . request_layout ) ( self , cx ) . 1 ;
element . draw ( bounds . origin , bounds . size . into ( ) , cx ) ;
}
2024-01-08 18:31:50 +00:00
state . cache_key = Some ( ViewCacheKey {
bounds ,
stacking_order : cx . stacking_order ( ) . clone ( ) ,
content_mask : cx . content_mask ( ) ,
text_style : cx . text_style ( ) ,
} ) ;
} )
2023-11-19 03:05:47 +00:00
}
}
2023-11-22 18:19:43 +00:00
impl < V : 'static + Render > IntoElement for View < V > {
2023-11-19 03:05:47 +00:00
type Element = View < V > ;
2023-09-22 14:33:51 +00:00
2023-11-14 08:15:48 +00:00
fn element_id ( & self ) -> Option < ElementId > {
2023-11-22 01:11:38 +00:00
Some ( ElementId ::from_entity_id ( self . model . entity_id ) )
2023-10-11 17:40:42 +00:00
}
2023-11-22 18:19:43 +00:00
fn into_element ( self ) -> Self ::Element {
2023-11-19 03:05:47 +00:00
self
2023-09-22 14:33:51 +00:00
}
2023-11-19 03:05:47 +00:00
}
2023-09-22 14:33:51 +00:00
2023-11-22 18:19:43 +00:00
impl IntoElement for AnyView {
2023-11-19 03:05:47 +00:00
type Element = Self ;
2023-11-19 04:51:47 +00:00
fn element_id ( & self ) -> Option < ElementId > {
2023-11-22 01:11:38 +00:00
Some ( ElementId ::from_entity_id ( self . model . entity_id ) )
2023-11-19 04:51:47 +00:00
}
2023-11-22 18:19:43 +00:00
fn into_element ( self ) -> Self ::Element {
2023-11-19 03:05:47 +00:00
self
2023-10-12 17:30:00 +00:00
}
}
2024-01-17 18:21:29 +00:00
/// A weak, dynamically-typed view handle that does not prevent the view from being released.
2023-10-31 15:19:46 +00:00
pub struct AnyWeakView {
model : AnyWeakModel ,
2023-11-20 19:21:42 +00:00
layout : fn ( & AnyView , & mut WindowContext ) -> ( LayoutId , AnyElement ) ,
2023-10-31 15:19:46 +00:00
}
impl AnyWeakView {
2024-01-17 18:21:29 +00:00
/// Convert to a strongly-typed handle if the referenced view has not yet been released.
2023-10-31 15:19:46 +00:00
pub fn upgrade ( & self ) -> Option < AnyView > {
let model = self . model . upgrade ( ) ? ;
Some ( AnyView {
model ,
2024-01-08 18:07:20 +00:00
request_layout : self . layout ,
cache : false ,
2023-10-31 15:19:46 +00:00
} )
}
}
2023-11-20 19:21:42 +00:00
impl < V : 'static + Render > From < WeakView < V > > for AnyWeakView {
2023-11-03 10:36:18 +00:00
fn from ( view : WeakView < V > ) -> Self {
Self {
model : view . model . into ( ) ,
2024-01-08 18:07:20 +00:00
layout : any_view ::request_layout ::< V > ,
2023-11-03 10:36:18 +00:00
}
}
}
2023-12-14 22:15:56 +00:00
impl PartialEq for AnyWeakView {
fn eq ( & self , other : & Self ) -> bool {
self . model = = other . model
}
}
impl std ::fmt ::Debug for AnyWeakView {
fn fmt ( & self , f : & mut fmt ::Formatter < '_ > ) -> fmt ::Result {
f . debug_struct ( " AnyWeakView " )
. field ( " entity_id " , & self . model . entity_id )
. finish_non_exhaustive ( )
}
}
2023-11-03 10:36:18 +00:00
mod any_view {
2023-12-31 15:33:40 +00:00
use crate ::{ AnyElement , AnyView , IntoElement , LayoutId , Render , WindowContext } ;
2023-11-03 10:36:18 +00:00
2024-01-08 18:07:20 +00:00
pub ( crate ) fn request_layout < V : 'static + Render > (
2023-11-03 10:36:18 +00:00
view : & AnyView ,
cx : & mut WindowContext ,
2023-11-20 19:21:42 +00:00
) -> ( LayoutId , AnyElement ) {
2023-11-22 01:11:38 +00:00
let view = view . clone ( ) . downcast ::< V > ( ) . unwrap ( ) ;
2023-12-31 15:33:40 +00:00
let mut element = view . update ( cx , | view , cx | view . render ( cx ) . into_any_element ( ) ) ;
2024-01-02 17:27:09 +00:00
let layout_id = element . request_layout ( cx ) ;
2023-11-22 01:11:38 +00:00
( layout_id , element )
2023-11-03 10:36:18 +00:00
}
}