Merge ElementContext into WindowContext (#10979)

The new `ElementContext` was originally introduced to ensure the element
APIs could only be used inside of elements. Unfortunately, there were
many places where some of those APIs needed to be used, so
`WindowContext::with_element_context` was introduced, which defeated the
original safety purposes of having a specific context for elements.

This pull request merges `ElementContext` into `WindowContext` and adds
(debug) runtime checks to APIs that can only be used during certain
phases of element drawing.

Release Notes:

- N/A

---------

Co-authored-by: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Antonio Scandurra 2024-04-25 12:54:39 +02:00 committed by GitHub
parent 031580f4dc
commit 6a7761e620
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
29 changed files with 2378 additions and 2367 deletions

View file

@ -2,9 +2,9 @@ use std::{cell::RefCell, rc::Rc};
use gpui::{
anchored, deferred, div, point, prelude::FluentBuilder, px, AnchorCorner, AnyElement, Bounds,
DismissEvent, DispatchPhase, Element, ElementContext, ElementId, HitboxId, InteractiveElement,
IntoElement, LayoutId, ManagedView, MouseDownEvent, ParentElement, Pixels, Point, View,
VisualContext, WindowContext,
DismissEvent, DispatchPhase, Element, ElementId, HitboxId, InteractiveElement, IntoElement,
LayoutId, ManagedView, MouseDownEvent, ParentElement, Pixels, Point, View, VisualContext,
WindowContext,
};
use crate::prelude::*;
@ -112,8 +112,8 @@ impl<M: ManagedView> PopoverMenu<M> {
fn with_element_state<R>(
&mut self,
cx: &mut ElementContext,
f: impl FnOnce(&mut Self, &mut PopoverMenuElementState<M>, &mut ElementContext) -> R,
cx: &mut WindowContext,
f: impl FnOnce(&mut Self, &mut PopoverMenuElementState<M>, &mut WindowContext) -> R,
) -> R {
cx.with_element_state::<PopoverMenuElementState<M>, _>(
Some(self.id.clone()),
@ -173,7 +173,7 @@ impl<M: ManagedView> Element for PopoverMenu<M> {
fn request_layout(
&mut self,
cx: &mut ElementContext,
cx: &mut WindowContext,
) -> (gpui::LayoutId, Self::RequestLayoutState) {
self.with_element_state(cx, |this, element_state, cx| {
let mut menu_layout_id = None;
@ -221,7 +221,7 @@ impl<M: ManagedView> Element for PopoverMenu<M> {
&mut self,
_bounds: Bounds<Pixels>,
request_layout: &mut Self::RequestLayoutState,
cx: &mut ElementContext,
cx: &mut WindowContext,
) -> Option<HitboxId> {
self.with_element_state(cx, |_this, element_state, cx| {
if let Some(child) = request_layout.child_element.as_mut() {
@ -245,7 +245,7 @@ impl<M: ManagedView> Element for PopoverMenu<M> {
_: Bounds<gpui::Pixels>,
request_layout: &mut Self::RequestLayoutState,
child_hitbox: &mut Option<HitboxId>,
cx: &mut ElementContext,
cx: &mut WindowContext,
) {
self.with_element_state(cx, |_this, _element_state, cx| {
if let Some(mut child) = request_layout.child_element.take() {

View file

@ -2,9 +2,8 @@ use std::{cell::RefCell, rc::Rc};
use gpui::{
anchored, deferred, div, AnchorCorner, AnyElement, Bounds, DismissEvent, DispatchPhase,
Element, ElementContext, ElementId, Hitbox, InteractiveElement, IntoElement, LayoutId,
ManagedView, MouseButton, MouseDownEvent, ParentElement, Pixels, Point, View, VisualContext,
WindowContext,
Element, ElementId, Hitbox, InteractiveElement, IntoElement, LayoutId, ManagedView,
MouseButton, MouseDownEvent, ParentElement, Pixels, Point, View, VisualContext, WindowContext,
};
pub struct RightClickMenu<M: ManagedView> {
@ -41,8 +40,8 @@ impl<M: ManagedView> RightClickMenu<M> {
fn with_element_state<R>(
&mut self,
cx: &mut ElementContext,
f: impl FnOnce(&mut Self, &mut MenuHandleElementState<M>, &mut ElementContext) -> R,
cx: &mut WindowContext,
f: impl FnOnce(&mut Self, &mut MenuHandleElementState<M>, &mut WindowContext) -> R,
) -> R {
cx.with_element_state::<MenuHandleElementState<M>, _>(
Some(self.id.clone()),
@ -89,19 +88,24 @@ impl<M> Default for MenuHandleElementState<M> {
}
}
pub struct MenuHandleFrameState {
pub struct RequestLayoutState {
child_layout_id: Option<LayoutId>,
child_element: Option<AnyElement>,
menu_element: Option<AnyElement>,
}
pub struct PrepaintState {
hitbox: Hitbox,
child_bounds: Option<Bounds<Pixels>>,
}
impl<M: ManagedView> Element for RightClickMenu<M> {
type RequestLayoutState = MenuHandleFrameState;
type PrepaintState = Hitbox;
type RequestLayoutState = RequestLayoutState;
type PrepaintState = PrepaintState;
fn request_layout(
&mut self,
cx: &mut ElementContext,
cx: &mut WindowContext,
) -> (gpui::LayoutId, Self::RequestLayoutState) {
self.with_element_state(cx, |this, element_state, cx| {
let mut menu_layout_id = None;
@ -137,7 +141,7 @@ impl<M: ManagedView> Element for RightClickMenu<M> {
(
layout_id,
MenuHandleFrameState {
RequestLayoutState {
child_element,
child_layout_id,
menu_element,
@ -150,8 +154,8 @@ impl<M: ManagedView> Element for RightClickMenu<M> {
&mut self,
bounds: Bounds<Pixels>,
request_layout: &mut Self::RequestLayoutState,
cx: &mut ElementContext,
) -> Hitbox {
cx: &mut WindowContext,
) -> PrepaintState {
cx.with_element_id(Some(self.id.clone()), |cx| {
let hitbox = cx.insert_hitbox(bounds, false);
@ -163,7 +167,12 @@ impl<M: ManagedView> Element for RightClickMenu<M> {
menu.prepaint(cx);
}
hitbox
PrepaintState {
hitbox,
child_bounds: request_layout
.child_layout_id
.map(|layout_id| cx.layout_bounds(layout_id)),
}
})
}
@ -171,8 +180,8 @@ impl<M: ManagedView> Element for RightClickMenu<M> {
&mut self,
_bounds: Bounds<gpui::Pixels>,
request_layout: &mut Self::RequestLayoutState,
hitbox: &mut Self::PrepaintState,
cx: &mut ElementContext,
prepaint_state: &mut Self::PrepaintState,
cx: &mut WindowContext,
) {
self.with_element_state(cx, |this, element_state, cx| {
if let Some(mut child) = request_layout.child_element.take() {
@ -191,10 +200,9 @@ impl<M: ManagedView> Element for RightClickMenu<M> {
let attach = this.attach;
let menu = element_state.menu.clone();
let position = element_state.position.clone();
let child_layout_id = request_layout.child_layout_id;
let child_bounds = cx.layout_bounds(child_layout_id.unwrap());
let child_bounds = prepaint_state.child_bounds;
let hitbox_id = hitbox.id;
let hitbox_id = prepaint_state.hitbox.id;
cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
if phase == DispatchPhase::Bubble
&& event.button == MouseButton::Right
@ -219,7 +227,7 @@ impl<M: ManagedView> Element for RightClickMenu<M> {
.detach();
cx.focus_view(&new_menu);
*menu.borrow_mut() = Some(new_menu);
*position.borrow_mut() = if child_layout_id.is_some() {
*position.borrow_mut() = if let Some(child_bounds) = child_bounds {
if let Some(attach) = attach {
attach.corner(child_bounds)
} else {

View file

@ -2,9 +2,9 @@
pub use gpui::prelude::*;
pub use gpui::{
div, px, relative, rems, AbsoluteLength, DefiniteLength, Div, Element, ElementContext,
ElementId, InteractiveElement, ParentElement, Pixels, Rems, RenderOnce, SharedString, Styled,
ViewContext, WindowContext,
div, px, relative, rems, AbsoluteLength, DefiniteLength, Div, Element, ElementId,
InteractiveElement, ParentElement, Pixels, Rems, RenderOnce, SharedString, Styled, ViewContext,
WindowContext,
};
pub use crate::clickable::*;