This commit is contained in:
Nathan Sobo 2023-04-10 17:27:47 -06:00
parent 6638407ff9
commit 3de8fe0f87
21 changed files with 675 additions and 694 deletions

View file

@ -69,7 +69,7 @@ pub trait Entity: 'static {
pub trait View: Entity + Sized { pub trait View: Entity + Sized {
fn ui_name() -> &'static str; fn ui_name() -> &'static str;
fn render(&mut self, cx: &mut RenderContext<'_, Self>) -> ElementBox<Self>; fn render(&mut self, cx: &mut ViewContext<'_, '_, Self>) -> ElementBox<Self>;
fn focus_in(&mut self, _: AnyViewHandle, _: &mut ViewContext<Self>) {} fn focus_in(&mut self, _: AnyViewHandle, _: &mut ViewContext<Self>) {}
fn focus_out(&mut self, _: AnyViewHandle, _: &mut ViewContext<Self>) {} fn focus_out(&mut self, _: AnyViewHandle, _: &mut ViewContext<Self>) {}
fn key_down(&mut self, _: &KeyDownEvent, _: &mut ViewContext<Self>) -> bool { fn key_down(&mut self, _: &KeyDownEvent, _: &mut ViewContext<Self>) -> bool {
@ -2983,7 +2983,7 @@ where
params: RenderParams, params: RenderParams,
cx: &mut WindowContext<'a, 'b>, cx: &mut WindowContext<'a, 'b>,
) -> Box<dyn RenderedView> { ) -> Box<dyn RenderedView> {
View::render(self, &mut RenderContext::new(params, cx)) View::render(self, &mut ViewContext::new(params, cx))
} }
fn focus_in<'a, 'b>( fn focus_in<'a, 'b>(
@ -3359,7 +3359,7 @@ impl<'a, 'b, T: View> DerefMut for ViewContext<'a, 'b, T> {
} }
} }
impl<'a, 'b, T: View> ViewContext<'a, 'b, T> { impl<'a, 'b, V: View> ViewContext<'a, 'b, V> {
fn new(window_context: &'b mut WindowContext<'a, 'b>, view_id: usize) -> Self { fn new(window_context: &'b mut WindowContext<'a, 'b>, view_id: usize) -> Self {
Self { Self {
window_context, window_context,
@ -3368,7 +3368,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> {
} }
} }
pub fn handle(&self) -> ViewHandle<T> { pub fn handle(&self) -> ViewHandle<V> {
ViewHandle::new( ViewHandle::new(
self.window_id, self.window_id,
self.view_id, self.view_id,
@ -3376,7 +3376,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> {
) )
} }
pub fn weak_handle(&self) -> WeakViewHandle<T> { pub fn weak_handle(&self) -> WeakViewHandle<V> {
WeakViewHandle::new(self.window_id, self.view_id) WeakViewHandle::new(self.window_id, self.view_id)
} }
@ -3449,7 +3449,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> {
pub fn on_window_should_close<F>(&mut self, mut callback: F) pub fn on_window_should_close<F>(&mut self, mut callback: F)
where where
F: 'static + FnMut(&mut T, &mut ViewContext<T>) -> bool, F: 'static + FnMut(&mut V, &mut ViewContext<V>) -> bool,
{ {
let window_id = self.window_id(); let window_id = self.window_id();
let view = self.weak_handle(); let view = self.weak_handle();
@ -3511,10 +3511,10 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> {
); );
} }
pub fn replace_root_view<V, F>(&mut self, build_root_view: F) -> ViewHandle<V> pub fn replace_root_view<W, F>(&mut self, build_root_view: F) -> ViewHandle<W>
where where
V: View, W: View,
F: FnOnce(&mut ViewContext<V>) -> V, F: FnOnce(&mut ViewContext<W>) -> W,
{ {
let window_id = self.window_id; let window_id = self.window_id;
self.update(|this| { self.update(|this| {
@ -3533,7 +3533,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> {
E: Entity, E: Entity,
E::Event: 'static, E::Event: 'static,
H: Handle<E>, H: Handle<E>,
F: 'static + FnMut(&mut T, H, &E::Event, &mut ViewContext<T>), F: 'static + FnMut(&mut V, H, &E::Event, &mut ViewContext<V>),
{ {
let subscriber = self.weak_handle(); let subscriber = self.weak_handle();
self.window_context self.window_context
@ -3553,7 +3553,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> {
where where
E: Entity, E: Entity,
H: Handle<E>, H: Handle<E>,
F: 'static + FnMut(&mut T, H, &mut ViewContext<T>), F: 'static + FnMut(&mut V, H, &mut ViewContext<V>),
{ {
let observer = self.weak_handle(); let observer = self.weak_handle();
self.window_context self.window_context
@ -3572,7 +3572,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> {
pub fn observe_global<G, F>(&mut self, mut callback: F) -> Subscription pub fn observe_global<G, F>(&mut self, mut callback: F) -> Subscription
where where
G: Any, G: Any,
F: 'static + FnMut(&mut T, &mut ViewContext<T>), F: 'static + FnMut(&mut V, &mut ViewContext<V>),
{ {
let observer = self.weak_handle(); let observer = self.weak_handle();
self.window_context.observe_global::<G, _>(move |cx| { self.window_context.observe_global::<G, _>(move |cx| {
@ -3582,10 +3582,10 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> {
}) })
} }
pub fn observe_focus<F, V>(&mut self, handle: &ViewHandle<V>, mut callback: F) -> Subscription pub fn observe_focus<F, W>(&mut self, handle: &ViewHandle<W>, mut callback: F) -> Subscription
where where
F: 'static + FnMut(&mut T, ViewHandle<V>, bool, &mut ViewContext<T>), F: 'static + FnMut(&mut V, ViewHandle<W>, bool, &mut ViewContext<V>),
V: View, W: View,
{ {
let observer = self.weak_handle(); let observer = self.weak_handle();
self.window_context self.window_context
@ -3605,7 +3605,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> {
where where
E: Entity, E: Entity,
H: Handle<E>, H: Handle<E>,
F: 'static + FnMut(&mut T, &E, &mut ViewContext<T>), F: 'static + FnMut(&mut V, &E, &mut ViewContext<V>),
{ {
let observer = self.weak_handle(); let observer = self.weak_handle();
self.window_context self.window_context
@ -3620,7 +3620,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> {
pub fn observe_actions<F>(&mut self, mut callback: F) -> Subscription pub fn observe_actions<F>(&mut self, mut callback: F) -> Subscription
where where
F: 'static + FnMut(&mut T, TypeId, &mut ViewContext<T>), F: 'static + FnMut(&mut V, TypeId, &mut ViewContext<V>),
{ {
let observer = self.weak_handle(); let observer = self.weak_handle();
self.window_context.observe_actions(move |action_id, cx| { self.window_context.observe_actions(move |action_id, cx| {
@ -3634,7 +3634,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> {
pub fn observe_window_activation<F>(&mut self, mut callback: F) -> Subscription pub fn observe_window_activation<F>(&mut self, mut callback: F) -> Subscription
where where
F: 'static + FnMut(&mut T, bool, &mut ViewContext<T>), F: 'static + FnMut(&mut V, bool, &mut ViewContext<V>),
{ {
let observer = self.weak_handle(); let observer = self.weak_handle();
self.window_context self.window_context
@ -3652,7 +3652,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> {
pub fn observe_fullscreen<F>(&mut self, mut callback: F) -> Subscription pub fn observe_fullscreen<F>(&mut self, mut callback: F) -> Subscription
where where
F: 'static + FnMut(&mut T, bool, &mut ViewContext<T>), F: 'static + FnMut(&mut V, bool, &mut ViewContext<V>),
{ {
let observer = self.weak_handle(); let observer = self.weak_handle();
self.window_context self.window_context
@ -3672,11 +3672,11 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> {
where where
F: 'static F: 'static
+ FnMut( + FnMut(
&mut T, &mut V,
&Keystroke, &Keystroke,
Option<&Box<dyn Action>>, Option<&Box<dyn Action>>,
&MatchResult, &MatchResult,
&mut ViewContext<T>, &mut ViewContext<V>,
) -> bool, ) -> bool,
{ {
let observer = self.weak_handle(); let observer = self.weak_handle();
@ -3697,7 +3697,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> {
pub fn observe_window_bounds<F>(&mut self, mut callback: F) -> Subscription pub fn observe_window_bounds<F>(&mut self, mut callback: F) -> Subscription
where where
F: 'static + FnMut(&mut T, WindowBounds, Uuid, &mut ViewContext<T>), F: 'static + FnMut(&mut V, WindowBounds, Uuid, &mut ViewContext<V>),
{ {
let observer = self.weak_handle(); let observer = self.weak_handle();
self.window_context self.window_context
@ -3715,7 +3715,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> {
pub fn observe_active_labeled_tasks<F>(&mut self, mut callback: F) -> Subscription pub fn observe_active_labeled_tasks<F>(&mut self, mut callback: F) -> Subscription
where where
F: 'static + FnMut(&mut T, &mut ViewContext<T>), F: 'static + FnMut(&mut V, &mut ViewContext<V>),
{ {
let observer = self.weak_handle(); let observer = self.weak_handle();
self.window_context.observe_active_labeled_tasks(move |cx| { self.window_context.observe_active_labeled_tasks(move |cx| {
@ -3730,7 +3730,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> {
}) })
} }
pub fn emit(&mut self, payload: T::Event) { pub fn emit(&mut self, payload: V::Event) {
self.window_context self.window_context
.pending_effects .pending_effects
.push_back(Effect::Event { .push_back(Effect::Event {
@ -3754,7 +3754,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> {
.dispatch_any_action_at(self.window_id, self.view_id, action) .dispatch_any_action_at(self.window_id, self.view_id, action)
} }
pub fn defer(&mut self, callback: impl 'static + FnOnce(&mut T, &mut ViewContext<T>)) { pub fn defer(&mut self, callback: impl 'static + FnOnce(&mut V, &mut ViewContext<V>)) {
let handle = self.handle(); let handle = self.handle();
self.window_context.defer(move |cx| { self.window_context.defer(move |cx| {
handle.update(cx, |view, cx| { handle.update(cx, |view, cx| {
@ -3765,7 +3765,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> {
pub fn after_window_update( pub fn after_window_update(
&mut self, &mut self,
callback: impl 'static + FnOnce(&mut T, &mut ViewContext<T>), callback: impl 'static + FnOnce(&mut V, &mut ViewContext<V>),
) { ) {
let handle = self.handle(); let handle = self.handle();
self.window_context.after_window_update(move |cx| { self.window_context.after_window_update(move |cx| {
@ -3781,7 +3781,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> {
pub fn spawn_labeled<F, Fut, S>(&mut self, task_label: &'static str, f: F) -> Task<S> pub fn spawn_labeled<F, Fut, S>(&mut self, task_label: &'static str, f: F) -> Task<S>
where where
F: FnOnce(ViewHandle<T>, AsyncAppContext) -> Fut, F: FnOnce(ViewHandle<V>, AsyncAppContext) -> Fut,
Fut: 'static + Future<Output = S>, Fut: 'static + Future<Output = S>,
S: 'static, S: 'static,
{ {
@ -3792,7 +3792,7 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> {
pub fn spawn<F, Fut, S>(&mut self, f: F) -> Task<S> pub fn spawn<F, Fut, S>(&mut self, f: F) -> Task<S>
where where
F: FnOnce(ViewHandle<T>, AsyncAppContext) -> Fut, F: FnOnce(ViewHandle<V>, AsyncAppContext) -> Fut,
Fut: 'static + Future<Output = S>, Fut: 'static + Future<Output = S>,
S: 'static, S: 'static,
{ {
@ -3802,79 +3802,13 @@ impl<'a, 'b, T: View> ViewContext<'a, 'b, T> {
pub fn spawn_weak<F, Fut, S>(&mut self, f: F) -> Task<S> pub fn spawn_weak<F, Fut, S>(&mut self, f: F) -> Task<S>
where where
F: FnOnce(WeakViewHandle<T>, AsyncAppContext) -> Fut, F: FnOnce(WeakViewHandle<V>, AsyncAppContext) -> Fut,
Fut: 'static + Future<Output = S>, Fut: 'static + Future<Output = S>,
S: 'static, S: 'static,
{ {
let handle = self.weak_handle(); let handle = self.weak_handle();
self.window_context.spawn(|cx| f(handle, cx)) self.window_context.spawn(|cx| f(handle, cx))
} }
}
pub struct RenderParams {
pub window_id: usize,
pub view_id: usize,
pub titlebar_height: f32,
pub hovered_region_ids: HashSet<MouseRegionId>,
pub clicked_region_ids: Option<(HashSet<MouseRegionId>, MouseButton)>,
pub refreshing: bool,
pub appearance: Appearance,
}
#[derive(Debug, Clone, Default)]
pub struct MouseState {
pub(crate) hovered: bool,
pub(crate) clicked: Option<MouseButton>,
pub(crate) accessed_hovered: bool,
pub(crate) accessed_clicked: bool,
}
impl MouseState {
pub fn hovered(&mut self) -> bool {
self.accessed_hovered = true;
self.hovered
}
pub fn clicked(&mut self) -> Option<MouseButton> {
self.accessed_clicked = true;
self.clicked
}
pub fn accessed_hovered(&self) -> bool {
self.accessed_hovered
}
pub fn accessed_clicked(&self) -> bool {
self.accessed_clicked
}
}
impl<'a, V: View> RenderContext<'a, V> {
fn new(params: RenderParams, app: &'a mut AppContext) -> Self {
Self {
app,
window_id: params.window_id,
view_id: params.view_id,
view_type: PhantomData,
titlebar_height: params.titlebar_height,
hovered_region_ids: params.hovered_region_ids.clone(),
clicked_region_ids: params.clicked_region_ids.clone(),
refreshing: params.refreshing,
appearance: params.appearance,
}
}
pub fn handle(&self) -> WeakViewHandle<V> {
WeakViewHandle::new(self.window_id, self.view_id)
}
pub fn window_id(&self) -> usize {
self.window_id
}
pub fn view_id(&self) -> usize {
self.view_id
}
pub fn mouse_state<Tag: 'static>(&self, region_id: usize) -> MouseState { pub fn mouse_state<Tag: 'static>(&self, region_id: usize) -> MouseState {
let region_id = MouseRegionId::new::<Tag>(self.view_id, region_id); let region_id = MouseRegionId::new::<Tag>(self.view_id, region_id);
@ -3916,62 +3850,6 @@ impl<'a, V: View> RenderContext<'a, V> {
} }
} }
impl<V: View> Deref for RenderContext<'_, V> {
type Target = AppContext;
fn deref(&self) -> &Self::Target {
self.app
}
}
impl<V: View> DerefMut for RenderContext<'_, V> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.app
}
}
impl<V: View> ReadModel for RenderContext<'_, V> {
fn read_model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
self.app.read_model(handle)
}
}
impl<V: View> UpdateModel for RenderContext<'_, V> {
fn update_model<T: Entity, O>(
&mut self,
handle: &ModelHandle<T>,
update: &mut dyn FnMut(&mut T, &mut ModelContext<T>) -> O,
) -> O {
self.app.update_model(handle, update)
}
}
impl<V: View> ReadView for RenderContext<'_, V> {
fn read_view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
self.app.read_view(handle)
}
}
impl<'a, 'b, M> Deref for ViewContext<'a, 'b, M> {
type Target = WindowContext<'a, 'b>;
fn deref(&self) -> &Self::Target {
&self.window_context
}
}
impl<M> DerefMut for ViewContext<'_, '_, M> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.window_context
}
}
impl<V> ReadModel for ViewContext<'_, '_, V> {
fn read_model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
self.window_context.read_model(handle)
}
}
impl<V> UpgradeModelHandle for ViewContext<'_, '_, V> { impl<V> UpgradeModelHandle for ViewContext<'_, '_, V> {
fn upgrade_model_handle<T: Entity>( fn upgrade_model_handle<T: Entity>(
&self, &self,
@ -3999,16 +3877,6 @@ impl<V> UpgradeViewHandle for ViewContext<'_, '_, V> {
} }
} }
impl<V: View> UpgradeViewHandle for RenderContext<'_, V> {
fn upgrade_view_handle<T: View>(&self, handle: &WeakViewHandle<T>) -> Option<ViewHandle<T>> {
self.app.upgrade_view_handle(handle)
}
fn upgrade_any_view_handle(&self, handle: &AnyWeakViewHandle) -> Option<AnyViewHandle> {
self.app.upgrade_any_view_handle(handle)
}
}
impl<V: View> UpdateModel for ViewContext<'_, '_, V> { impl<V: View> UpdateModel for ViewContext<'_, '_, V> {
fn update_model<T: Entity, O>( fn update_model<T: Entity, O>(
&mut self, &mut self,
@ -4038,6 +3906,44 @@ impl<V: View> UpdateView for ViewContext<'_, '_, V> {
} }
} }
pub struct RenderParams {
pub window_id: usize,
pub view_id: usize,
pub titlebar_height: f32,
pub hovered_region_ids: HashSet<MouseRegionId>,
pub clicked_region_ids: Option<(HashSet<MouseRegionId>, MouseButton)>,
pub refreshing: bool,
pub appearance: Appearance,
}
#[derive(Debug, Clone, Default)]
pub struct MouseState {
pub(crate) hovered: bool,
pub(crate) clicked: Option<MouseButton>,
pub(crate) accessed_hovered: bool,
pub(crate) accessed_clicked: bool,
}
impl MouseState {
pub fn hovered(&mut self) -> bool {
self.accessed_hovered = true;
self.hovered
}
pub fn clicked(&mut self) -> Option<MouseButton> {
self.accessed_clicked = true;
self.clicked
}
pub fn accessed_hovered(&self) -> bool {
self.accessed_hovered
}
pub fn accessed_clicked(&self) -> bool {
self.accessed_clicked
}
}
pub trait Handle<T> { pub trait Handle<T> {
type Weak: 'static; type Weak: 'static;
fn id(&self) -> usize; fn id(&self) -> usize;
@ -5078,7 +4984,7 @@ mod tests {
} }
impl super::View for View { impl super::View for View {
fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox<Self> { fn render(&mut self, _: &mut ViewContext<Self>) -> ElementBox<Self> {
post_inc(&mut self.render_count); post_inc(&mut self.render_count);
Empty::new().boxed() Empty::new().boxed()
} }
@ -5131,7 +5037,7 @@ mod tests {
} }
impl super::View for View { impl super::View for View {
fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox<Self> { fn render(&mut self, _: &mut ViewContext<Self>) -> ElementBox<Self> {
Empty::new().boxed() Empty::new().boxed()
} }
@ -5195,7 +5101,7 @@ mod tests {
} }
impl super::View for View { impl super::View for View {
fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox<Self> { fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox<Self> {
enum Handler {} enum Handler {}
let mouse_down_count = self.mouse_down_count.clone(); let mouse_down_count = self.mouse_down_count.clone();
MouseEventHandler::<Handler>::new(0, cx, |_, _| Empty::new().boxed()) MouseEventHandler::<Handler>::new(0, cx, |_, _| Empty::new().boxed())
@ -5261,7 +5167,7 @@ mod tests {
"View" "View"
} }
fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox<Self> { fn render(&mut self, _: &mut ViewContext<Self>) -> ElementBox<Self> {
Empty::new().boxed() Empty::new().boxed()
} }
} }
@ -5779,7 +5685,7 @@ mod tests {
} }
impl super::View for View { impl super::View for View {
fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox<Self> { fn render(&mut self, _: &mut ViewContext<Self>) -> ElementBox<Self> {
Empty::new().boxed() Empty::new().boxed()
} }
@ -5844,7 +5750,7 @@ mod tests {
} }
impl super::View for View { impl super::View for View {
fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox<Self> { fn render(&mut self, _: &mut ViewContext<Self>) -> ElementBox<Self> {
Empty::new().boxed() Empty::new().boxed()
} }
@ -6020,7 +5926,7 @@ mod tests {
} }
impl View for ViewA { impl View for ViewA {
fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox<Self> { fn render(&mut self, _: &mut ViewContext<Self>) -> ElementBox<Self> {
Empty::new().boxed() Empty::new().boxed()
} }
@ -6038,7 +5944,7 @@ mod tests {
} }
impl View for ViewB { impl View for ViewB {
fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox<Self> { fn render(&mut self, _: &mut ViewContext<Self>) -> ElementBox<Self> {
Empty::new().boxed() Empty::new().boxed()
} }
@ -6190,7 +6096,7 @@ mod tests {
} }
impl super::View for View { impl super::View for View {
fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox<Self> { fn render(&mut self, _: &mut ViewContext<Self>) -> ElementBox<Self> {
Empty::new().boxed() Empty::new().boxed()
} }
@ -6317,7 +6223,7 @@ mod tests {
} }
impl super::View for View1 { impl super::View for View1 {
fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox<Self> { fn render(&mut self, _: &mut ViewContext<Self>) -> ElementBox<Self> {
Empty::new().boxed() Empty::new().boxed()
} }
fn ui_name() -> &'static str { fn ui_name() -> &'static str {
@ -6325,7 +6231,7 @@ mod tests {
} }
} }
impl super::View for View2 { impl super::View for View2 {
fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox<Self> { fn render(&mut self, _: &mut ViewContext<Self>) -> ElementBox<Self> {
Empty::new().boxed() Empty::new().boxed()
} }
fn ui_name() -> &'static str { fn ui_name() -> &'static str {
@ -6500,7 +6406,7 @@ mod tests {
"test view" "test view"
} }
fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox<Self> { fn render(&mut self, _: &mut ViewContext<Self>) -> ElementBox<Self> {
Empty::new().boxed() Empty::new().boxed()
} }
} }
@ -6562,7 +6468,7 @@ mod tests {
"test view" "test view"
} }
fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox<Self> { fn render(&mut self, _: &mut ViewContext<Self>) -> ElementBox<Self> {
Empty::new().named(format!("render count: {}", post_inc(&mut self.0))) Empty::new().named(format!("render count: {}", post_inc(&mut self.0)))
} }
} }
@ -6651,7 +6557,7 @@ mod tests {
"test view" "test view"
} }
fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox<Self> { fn render(&mut self, _: &mut ViewContext<Self>) -> ElementBox<Self> {
Empty::new().boxed() Empty::new().boxed()
} }
} }
@ -6731,7 +6637,7 @@ mod tests {
"child view" "child view"
} }
fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox<Self> { fn render(&mut self, _: &mut ViewContext<Self>) -> ElementBox<Self> {
self.rendered.set(true); self.rendered.set(true);
Empty::new().boxed() Empty::new().boxed()
} }
@ -6756,7 +6662,7 @@ mod tests {
"parent view" "parent view"
} }
fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox<Self> { fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox<Self> {
if let Some(child) = self.child.as_ref() { if let Some(child) = self.child.as_ref() {
ChildView::new(child, cx).boxed() ChildView::new(child, cx).boxed()
} else { } else {
@ -6798,7 +6704,7 @@ mod tests {
"TestView" "TestView"
} }
fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox<Self> { fn render(&mut self, _: &mut ViewContext<Self>) -> ElementBox<Self> {
Empty::new().boxed() Empty::new().boxed()
} }
} }

View file

@ -74,7 +74,7 @@ impl TestAppContext {
pub fn dispatch_action<A: Action>(&self, window_id: usize, action: A) { pub fn dispatch_action<A: Action>(&self, window_id: usize, action: A) {
let mut cx = self.cx.borrow_mut(); let mut cx = self.cx.borrow_mut();
if let Some(view_id) = cx.focused_view_id(window_id) { if let Some(view_id) = cx.focused_view_id {
cx.handle_dispatch_action_from_effect(window_id, Some(view_id), &action); cx.handle_dispatch_action_from_effect(window_id, Some(view_id), &action);
} }
} }
@ -169,11 +169,11 @@ impl TestAppContext {
pub fn render<F, V, T>(&mut self, handle: &ViewHandle<V>, f: F) -> T pub fn render<F, V, T>(&mut self, handle: &ViewHandle<V>, f: F) -> T
where where
F: FnOnce(&mut V, &mut RenderContext<V>) -> T, F: FnOnce(&mut V, &mut ViewContext<V>) -> T,
V: View, V: View,
{ {
handle.update(&mut *self.cx.borrow_mut(), |view, cx| { handle.update(&mut *self.cx.borrow_mut(), |view, cx| {
let mut render_cx = RenderContext { let mut render_cx = ViewContext {
app: cx, app: cx,
window_id: handle.window_id(), window_id: handle.window_id(),
view_id: handle.id(), view_id: handle.id(),

View file

@ -87,6 +87,7 @@ pub struct WindowContext<'a: 'b, 'b> {
app_context: &'a mut AppContext, app_context: &'a mut AppContext,
pub(crate) window: &'b mut Window, // TODO: make this private? pub(crate) window: &'b mut Window, // TODO: make this private?
pub(crate) window_id: usize, pub(crate) window_id: usize,
pub refreshing: bool,
} }
impl Deref for WindowContext<'_, '_> { impl Deref for WindowContext<'_, '_> {

View file

@ -27,12 +27,11 @@ pub use self::{
}; };
use self::{clipped::Clipped, expanded::Expanded}; use self::{clipped::Clipped, expanded::Expanded};
use crate::{ use crate::{
app::window::MeasurementContext,
geometry::{ geometry::{
rect::RectF, rect::RectF,
vector::{vec2f, Vector2F}, vector::{vec2f, Vector2F},
}, },
json, Action, RenderContext, SceneBuilder, SizeConstraint, View, ViewContext, json, Action, SceneBuilder, SizeConstraint, View, ViewContext,
}; };
use core::panic; use core::panic;
use json::ToJson; use json::ToJson;
@ -62,7 +61,7 @@ trait AnyElement<V: View> {
cx: &ViewContext<V>, cx: &ViewContext<V>,
) -> Option<RectF>; ) -> Option<RectF>;
fn debug(&self, view: &V, cx: &mut ViewContext<V>) -> serde_json::Value; fn debug(&self, view: &V, cx: &ViewContext<V>) -> serde_json::Value;
fn size(&self) -> Vector2F; fn size(&self) -> Vector2F;
@ -82,6 +81,7 @@ pub trait Element<V: View> {
fn paint( fn paint(
&mut self, &mut self,
scene: &mut SceneBuilder,
bounds: RectF, bounds: RectF,
visible_bounds: RectF, visible_bounds: RectF,
layout: &mut Self::LayoutState, layout: &mut Self::LayoutState,
@ -133,81 +133,81 @@ pub trait Element<V: View> {
} }
} }
fn constrained(self) -> ConstrainedBox fn constrained(self) -> ConstrainedBox<V>
where where
Self: 'static + Sized, Self: 'static + Sized,
{ {
ConstrainedBox::new(self.boxed()) ConstrainedBox::new(self.boxed())
} }
fn aligned(self) -> Align fn aligned(self) -> Align<V>
where where
Self: 'static + Sized, Self: 'static + Sized,
{ {
Align::new(self.boxed()) Align::new(self.boxed())
} }
fn clipped(self) -> Clipped fn clipped(self) -> Clipped<V>
where where
Self: 'static + Sized, Self: 'static + Sized,
{ {
Clipped::new(self.boxed()) Clipped::new(self.boxed())
} }
fn contained(self) -> Container fn contained(self) -> Container<V>
where where
Self: 'static + Sized, Self: 'static + Sized,
{ {
Container::new(self.boxed()) Container::new(self.boxed())
} }
fn expanded(self) -> Expanded fn expanded(self) -> Expanded<V>
where where
Self: 'static + Sized, Self: 'static + Sized,
{ {
Expanded::new(self.boxed()) Expanded::new(self.boxed())
} }
fn flex(self, flex: f32, expanded: bool) -> FlexItem fn flex(self, flex: f32, expanded: bool) -> FlexItem<V>
where where
Self: 'static + Sized, Self: 'static + Sized,
{ {
FlexItem::new(self.boxed()).flex(flex, expanded) FlexItem::new(self.boxed()).flex(flex, expanded)
} }
fn flex_float(self) -> FlexItem fn flex_float(self) -> FlexItem<V>
where where
Self: 'static + Sized, Self: 'static + Sized,
{ {
FlexItem::new(self.boxed()).float() FlexItem::new(self.boxed()).float()
} }
fn with_tooltip<Tag: 'static, T: View>( fn with_tooltip<Tag: 'static>(
self, self,
id: usize, id: usize,
text: String, text: String,
action: Option<Box<dyn Action>>, action: Option<Box<dyn Action>>,
style: TooltipStyle, style: TooltipStyle,
cx: &mut RenderContext<T>, cx: &mut ViewContext<V>,
) -> Tooltip ) -> Tooltip<V>
where where
Self: 'static + Sized, Self: 'static + Sized,
{ {
Tooltip::new::<Tag, T>(id, text, action, style, self.boxed(), cx) Tooltip::new::<Tag>(id, text, action, style, self.boxed(), cx)
} }
fn with_resize_handle<Tag: 'static, T: View>( fn with_resize_handle<Tag: 'static>(
self, self,
element_id: usize, element_id: usize,
side: Side, side: Side,
handle_size: f32, handle_size: f32,
initial_size: f32, initial_size: f32,
cx: &mut RenderContext<T>, cx: &mut ViewContext<V>,
) -> Resizable ) -> Resizable<V>
where where
Self: 'static + Sized, Self: 'static + Sized,
{ {
Resizable::new::<Tag, T>( Resizable::new::<Tag>(
self.boxed(), self.boxed(),
element_id, element_id,
side, side,
@ -270,6 +270,7 @@ impl<V: View, E: Element<V>> AnyElement<V> for Lifecycle<V, E> {
fn paint( fn paint(
&mut self, &mut self,
scene: &mut SceneBuilder,
view: &mut V, view: &mut V,
origin: Vector2F, origin: Vector2F,
visible_bounds: RectF, visible_bounds: RectF,
@ -283,7 +284,7 @@ impl<V: View, E: Element<V>> AnyElement<V> for Lifecycle<V, E> {
mut layout, mut layout,
} => { } => {
let bounds = RectF::new(origin, size); let bounds = RectF::new(origin, size);
let paint = element.paint(view, bounds, visible_bounds, &mut layout, cx); let paint = element.paint(scene, bounds, visible_bounds, &mut layout, view, cx);
Lifecycle::PostPaint { Lifecycle::PostPaint {
element, element,
constraint, constraint,
@ -301,7 +302,7 @@ impl<V: View, E: Element<V>> AnyElement<V> for Lifecycle<V, E> {
.. ..
} => { } => {
let bounds = RectF::new(origin, bounds.size()); let bounds = RectF::new(origin, bounds.size());
let paint = element.paint(view, bounds, visible_bounds, &mut layout, cx); let paint = element.paint(scene, bounds, visible_bounds, &mut layout, view, cx);
Lifecycle::PostPaint { Lifecycle::PostPaint {
element, element,
constraint, constraint,
@ -334,12 +335,12 @@ impl<V: View, E: Element<V>> AnyElement<V> for Lifecycle<V, E> {
} = self } = self
{ {
element.rect_for_text_range( element.rect_for_text_range(
view,
range_utf16, range_utf16,
*bounds, *bounds,
*visible_bounds, *visible_bounds,
layout, layout,
paint, paint,
view,
cx, cx,
) )
} else { } else {
@ -374,7 +375,7 @@ impl<V: View, E: Element<V>> AnyElement<V> for Lifecycle<V, E> {
layout, layout,
paint, paint,
} => { } => {
let mut value = element.debug(view, *bounds, layout, paint, cx); let mut value = element.debug(*bounds, layout, paint, view, cx);
if let json::Value::Object(map) = &mut value { if let json::Value::Object(map) = &mut value {
let mut new_map: crate::json::Map<String, serde_json::Value> = let mut new_map: crate::json::Map<String, serde_json::Value> =
Default::default(); Default::default();
@ -403,7 +404,7 @@ impl<V: View, E: Element<V>> Default for Lifecycle<V, E> {
} }
pub struct ElementBox<V: View> { pub struct ElementBox<V: View> {
element: RefCell<dyn AnyElement<V>>, element: Box<RefCell<dyn AnyElement<V>>>,
view_type: PhantomData<V>, view_type: PhantomData<V>,
name: Option<Cow<'static, str>>, name: Option<Cow<'static, str>>,
} }
@ -420,8 +421,8 @@ impl<V: View> ElementBox<V> {
pub fn layout( pub fn layout(
&self, &self,
view: &mut V,
constraint: SizeConstraint, constraint: SizeConstraint,
view: &mut V,
cx: &mut ViewContext<V>, cx: &mut ViewContext<V>,
) -> Vector2F { ) -> Vector2F {
self.element.borrow_mut().layout(view, constraint, cx) self.element.borrow_mut().layout(view, constraint, cx)
@ -429,10 +430,10 @@ impl<V: View> ElementBox<V> {
pub fn paint( pub fn paint(
&self, &self,
view: &mut V,
scene: &mut SceneBuilder, scene: &mut SceneBuilder,
origin: Vector2F, origin: Vector2F,
visible_bounds: RectF, visible_bounds: RectF,
view: &mut V,
cx: &mut ViewContext<V>, cx: &mut ViewContext<V>,
) { ) {
self.element self.element
@ -442,8 +443,8 @@ impl<V: View> ElementBox<V> {
pub fn rect_for_text_range( pub fn rect_for_text_range(
&self, &self,
view: &V,
range_utf16: Range<usize>, range_utf16: Range<usize>,
view: &V,
cx: &ViewContext<V>, cx: &ViewContext<V>,
) -> Option<RectF> { ) -> Option<RectF> {
self.element self.element

View file

@ -1,3 +1,5 @@
use std::marker::PhantomData;
use super::Element; use super::Element;
use crate::{ use crate::{
json::{self, json}, json::{self, json},
@ -9,18 +11,19 @@ use pathfinder_geometry::{
vector::{vec2f, Vector2F}, vector::{vec2f, Vector2F},
}; };
pub struct Canvas<V, F>(F); pub struct Canvas<V, F>(F, PhantomData<V>);
impl<V: View, F> Canvas<V, F> impl<V, F> Canvas<V, F>
where where
V: View,
F: FnMut(&mut SceneBuilder, RectF, RectF, &mut V, &mut ViewContext<V>), F: FnMut(&mut SceneBuilder, RectF, RectF, &mut V, &mut ViewContext<V>),
{ {
pub fn new(f: F) -> Self { pub fn new(f: F) -> Self {
Self(f) Self(f, PhantomData)
} }
} }
impl<V, F> Element<V> for Canvas<V, F> impl<V: View, F> Element<V> for Canvas<V, F>
where where
F: FnMut(RectF, RectF, &mut ViewContext<V>), F: FnMut(RectF, RectF, &mut ViewContext<V>),
{ {
@ -30,7 +33,8 @@ where
fn layout( fn layout(
&mut self, &mut self,
constraint: crate::SizeConstraint, constraint: crate::SizeConstraint,
_: &mut crate::LayoutContext, _: &mut V,
_: &mut crate::ViewContext<V>,
) -> (Vector2F, Self::LayoutState) { ) -> (Vector2F, Self::LayoutState) {
let x = if constraint.max.x().is_finite() { let x = if constraint.max.x().is_finite() {
constraint.max.x() constraint.max.x()

View file

@ -308,7 +308,7 @@ impl<V: View> Element<V> for Container<V> {
_: &Self::LayoutState, _: &Self::LayoutState,
_: &Self::PaintState, _: &Self::PaintState,
view: &V, view: &V,
cx: &crate::DebugContext, cx: &ViewContext<V>,
) -> serde_json::Value { ) -> serde_json::Value {
json!({ json!({
"type": "Container", "type": "Container",

View file

@ -101,7 +101,7 @@ impl<V: View> Flex<V> {
vec2f(constraint.max.x(), child_max), vec2f(constraint.max.x(), child_max),
), ),
}; };
let child_size = child.layout(child_constraint, cx); let child_size = child.layout(child_constraint, view, cx);
*remaining_space -= child_size.along(self.axis); *remaining_space -= child_size.along(self.axis);
*remaining_flex -= flex; *remaining_flex -= flex;
*cross_axis_max = cross_axis_max.max(child_size.along(cross_axis)); *cross_axis_max = cross_axis_max.max(child_size.along(cross_axis));
@ -434,7 +434,7 @@ impl<V: View> Element<V> for FlexItem<V> {
view: &V, view: &V,
cx: &mut ViewContext<V>, cx: &mut ViewContext<V>,
) -> (Vector2F, Self::LayoutState) { ) -> (Vector2F, Self::LayoutState) {
let size = self.child.layout(constraint, cx); let size = self.child.layout(constraint, view, cx);
(size, ()) (size, ())
} }
@ -445,7 +445,7 @@ impl<V: View> Element<V> for FlexItem<V> {
visible_bounds: RectF, visible_bounds: RectF,
_: &mut Self::LayoutState, _: &mut Self::LayoutState,
view: &V, view: &V,
cx: &mut PaintContext, cx: &mut ViewContext<V>,
) -> Self::PaintState { ) -> Self::PaintState {
self.child self.child
.paint(scene, bounds.origin(), visible_bounds, view, cx) .paint(scene, bounds.origin(), visible_bounds, view, cx)

View file

@ -6,7 +6,7 @@ use crate::{
json::json, json::json,
Element, ElementBox, MouseRegion, SceneBuilder, SizeConstraint, View, ViewContext, Element, ElementBox, MouseRegion, SceneBuilder, SizeConstraint, View, ViewContext,
}; };
use std::{cell::RefCell, collections::VecDeque, ops::Range, rc::Rc}; use std::{cell::RefCell, collections::VecDeque, fmt::Debug, ops::Range, rc::Rc};
use sum_tree::{Bias, SumTree}; use sum_tree::{Bias, SumTree};
pub struct List<V: View> { pub struct List<V: View> {
@ -24,7 +24,7 @@ pub enum Orientation {
struct StateInner<V: View> { struct StateInner<V: View> {
last_layout_width: Option<f32>, last_layout_width: Option<f32>,
render_item: Box<dyn FnMut(usize, &V, &mut ViewContext<V>) -> Option<ElementBox<V>>>, render_item: Box<dyn FnMut(&mut V, usize, &mut ViewContext<V>) -> ElementBox<V>>,
rendered_range: Range<usize>, rendered_range: Range<usize>,
items: SumTree<ListItem<V>>, items: SumTree<ListItem<V>>,
logical_scroll_top: Option<ListOffset>, logical_scroll_top: Option<ListOffset>,
@ -40,14 +40,23 @@ pub struct ListOffset {
pub offset_in_item: f32, pub offset_in_item: f32,
} }
#[derive(Clone)]
enum ListItem<V: View> { enum ListItem<V: View> {
Unrendered, Unrendered,
Rendered(Rc<ElementBox<V>>), Rendered(Rc<ElementBox<V>>),
Removed(f32), Removed(f32),
} }
impl<V: View> std::fmt::Debug for ListItem<V> { impl<V: View> Clone for ListItem<V> {
fn clone(&self) -> Self {
match self {
Self::Unrendered => Self::Unrendered,
Self::Rendered(element) => Self::Rendered(element.clone()),
Self::Removed(height) => Self::Removed(*height),
}
}
}
impl<V: View> Debug for ListItem<V> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Self::Unrendered => write!(f, "Unrendered"), Self::Unrendered => write!(f, "Unrendered"),
@ -245,14 +254,13 @@ impl<V: View> Element<V> for List<V> {
bounds: RectF, bounds: RectF,
visible_bounds: RectF, visible_bounds: RectF,
scroll_top: &mut ListOffset, scroll_top: &mut ListOffset,
view: &V, view: &mut V,
cx: &mut ViewContext<V>, cx: &mut ViewContext<V>,
) { ) {
let visible_bounds = visible_bounds.intersection(bounds).unwrap_or_default(); let visible_bounds = visible_bounds.intersection(bounds).unwrap_or_default();
cx.scene.push_layer(Some(visible_bounds)); scene.push_layer(Some(visible_bounds));
scene.push_mouse_region(
cx.scene.push_mouse_region( MouseRegion::new::<Self>(cx.view_id(), 0, bounds).on_scroll({
MouseRegion::new::<Self>(cx.current_view_id(), 0, bounds).on_scroll({
let state = self.state.clone(); let state = self.state.clone();
let height = bounds.height(); let height = bounds.height();
let scroll_top = scroll_top.clone(); let scroll_top = scroll_top.clone();
@ -273,7 +281,7 @@ impl<V: View> Element<V> for List<V> {
element.paint(scene, origin, visible_bounds, view, cx); element.paint(scene, origin, visible_bounds, view, cx);
} }
cx.scene.pop_layer(); scene.pop_layer();
} }
fn rect_for_text_range( fn rect_for_text_range(
@ -349,9 +357,10 @@ impl<V: View> ListState<V> {
let handle = cx.weak_handle(); let handle = cx.weak_handle();
Self(Rc::new(RefCell::new(StateInner { Self(Rc::new(RefCell::new(StateInner {
last_layout_width: None, last_layout_width: None,
render_item: Box::new(move |ix, cx| { render_item: Box::new(move |ix, view, cx| {
let handle = handle.upgrade(cx)?; render_item(view, ix, cx)
Some(cx.render(&handle, |view, cx| render_item(view, ix, cx))) // let handle = handle.upgrade(cx)?;
// Some(cx.render(&handle, |view, cx| render_item(view, ix, cx)))
}), }),
rendered_range: 0..0, rendered_range: 0..0,
items, items,
@ -442,8 +451,8 @@ impl<V: View> StateInner<V> {
if let Some(ListItem::Rendered(element)) = existing_element { if let Some(ListItem::Rendered(element)) = existing_element {
Some(element.clone()) Some(element.clone())
} else { } else {
let mut element = (self.render_item)(ix, cx)?; let mut element = (self.render_item)(view, ix, cx);
element.layout(constraint, cx); element.layout(constraint, view, cx);
Some(element.into()) Some(element.into())
} }
} }
@ -460,7 +469,7 @@ impl<V: View> StateInner<V> {
&'a self, &'a self,
bounds: RectF, bounds: RectF,
scroll_top: &ListOffset, scroll_top: &ListOffset,
) -> impl Iterator<Item = (Rc<ElementBox>, Vector2F)> + 'a { ) -> impl Iterator<Item = (Rc<ElementBox<V>>, Vector2F)> + 'a {
let mut item_origin = bounds.origin() - vec2f(0., scroll_top.offset_in_item); let mut item_origin = bounds.origin() - vec2f(0., scroll_top.offset_in_item);
let mut cursor = self.items.cursor::<Count>(); let mut cursor = self.items.cursor::<Count>();
cursor.seek(&Count(scroll_top.item_ix), Bias::Right, &()); cursor.seek(&Count(scroll_top.item_ix), Bias::Right, &());
@ -637,262 +646,264 @@ mod tests {
#[crate::test(self)] #[crate::test(self)]
fn test_layout(cx: &mut crate::AppContext) { fn test_layout(cx: &mut crate::AppContext) {
let (_, view) = cx.add_window(Default::default(), |_| TestView); todo!()
let constraint = SizeConstraint::new(vec2f(0., 0.), vec2f(100., 40.)); // let (_, view) = cx.add_window(Default::default(), |_| TestView);
// let constraint = SizeConstraint::new(vec2f(0., 0.), vec2f(100., 40.));
let elements = Rc::new(RefCell::new(vec![(0, 20.), (1, 30.), (2, 100.)])); // let elements = Rc::new(RefCell::new(vec![(0, 20.), (1, 30.), (2, 100.)]));
let state = view.update(cx, |_, cx| { // let state = view.update(cx, |_, cx| {
ListState::new(elements.borrow().len(), Orientation::Top, 1000.0, cx, { // ListState::new(elements.borrow().len(), Orientation::Top, 1000.0, cx, {
let elements = elements.clone(); // let elements = elements.clone();
move |_, ix, _| { // move |_, ix, _| {
let (id, height) = elements.borrow()[ix]; // let (id, height) = elements.borrow()[ix];
TestElement::new(id, height).boxed() // TestElement::new(id, height).boxed()
} // }
}) // })
}); // });
let mut list = List::new(state.clone()); // let mut list = List::new(state.clone());
let (size, _) = list.layout( // let (size, _) = list.layout(
constraint, // constraint,
&mut presenter.build_layout_context(vec2f(100., 40.), false, cx), // &mut presenter.build_layout_context(vec2f(100., 40.), false, cx),
); // );
assert_eq!(size, vec2f(100., 40.)); // assert_eq!(size, vec2f(100., 40.));
assert_eq!( // assert_eq!(
state.0.borrow().items.summary().clone(), // state.0.borrow().items.summary().clone(),
ListItemSummary { // ListItemSummary {
count: 3, // count: 3,
rendered_count: 3, // rendered_count: 3,
unrendered_count: 0, // unrendered_count: 0,
height: 150. // height: 150.
} // }
); // );
state.0.borrow_mut().scroll( // state.0.borrow_mut().scroll(
&ListOffset { // &ListOffset {
item_ix: 0, // item_ix: 0,
offset_in_item: 0., // offset_in_item: 0.,
}, // },
40., // 40.,
vec2f(0., -54.), // vec2f(0., -54.),
true, // true,
&mut presenter.build_event_context(&mut Default::default(), cx), // &mut presenter.build_event_context(&mut Default::default(), cx),
); // );
let (_, logical_scroll_top) = list.layout( // let (_, logical_scroll_top) = list.layout(
constraint, // constraint,
&mut presenter.build_layout_context(vec2f(100., 40.), false, cx), // &mut presenter.build_layout_context(vec2f(100., 40.), false, cx),
); // );
assert_eq!( // assert_eq!(
logical_scroll_top, // logical_scroll_top,
ListOffset { // ListOffset {
item_ix: 2, // item_ix: 2,
offset_in_item: 4. // offset_in_item: 4.
} // }
); // );
assert_eq!(state.0.borrow().scroll_top(&logical_scroll_top), 54.); // assert_eq!(state.0.borrow().scroll_top(&logical_scroll_top), 54.);
elements.borrow_mut().splice(1..2, vec![(3, 40.), (4, 50.)]); // elements.borrow_mut().splice(1..2, vec![(3, 40.), (4, 50.)]);
elements.borrow_mut().push((5, 60.)); // elements.borrow_mut().push((5, 60.));
state.splice(1..2, 2); // state.splice(1..2, 2);
state.splice(4..4, 1); // state.splice(4..4, 1);
assert_eq!( // assert_eq!(
state.0.borrow().items.summary().clone(), // state.0.borrow().items.summary().clone(),
ListItemSummary { // ListItemSummary {
count: 5, // count: 5,
rendered_count: 2, // rendered_count: 2,
unrendered_count: 3, // unrendered_count: 3,
height: 120. // height: 120.
} // }
); // );
let (size, logical_scroll_top) = list.layout( // let (size, logical_scroll_top) = list.layout(
constraint, // constraint,
&mut presenter.build_layout_context(vec2f(100., 40.), false, cx), // &mut presenter.build_layout_context(vec2f(100., 40.), false, cx),
); // );
assert_eq!(size, vec2f(100., 40.)); // assert_eq!(size, vec2f(100., 40.));
assert_eq!( // assert_eq!(
state.0.borrow().items.summary().clone(), // state.0.borrow().items.summary().clone(),
ListItemSummary { // ListItemSummary {
count: 5, // count: 5,
rendered_count: 5, // rendered_count: 5,
unrendered_count: 0, // unrendered_count: 0,
height: 270. // height: 270.
} // }
); // );
assert_eq!( // assert_eq!(
logical_scroll_top, // logical_scroll_top,
ListOffset { // ListOffset {
item_ix: 3, // item_ix: 3,
offset_in_item: 4. // offset_in_item: 4.
} // }
); // );
assert_eq!(state.0.borrow().scroll_top(&logical_scroll_top), 114.); // assert_eq!(state.0.borrow().scroll_top(&logical_scroll_top), 114.);
} }
#[crate::test(self, iterations = 10, seed = 0)] #[crate::test(self, iterations = 10, seed = 0)]
fn test_random(cx: &mut crate::AppContext, mut rng: StdRng) { fn test_random(cx: &mut crate::AppContext, mut rng: StdRng) {
let operations = env::var("OPERATIONS") todo!()
.map(|i| i.parse().expect("invalid `OPERATIONS` variable")) // let operations = env::var("OPERATIONS")
.unwrap_or(10); // .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
// .unwrap_or(10);
let (window_id, view) = cx.add_window(Default::default(), |_| TestView); // let (window_id, view) = cx.add_window(Default::default(), |_| TestView);
let mut next_id = 0; // let mut next_id = 0;
let elements = Rc::new(RefCell::new( // let elements = Rc::new(RefCell::new(
(0..rng.gen_range(0..=20)) // (0..rng.gen_range(0..=20))
.map(|_| { // .map(|_| {
let id = next_id; // let id = next_id;
next_id += 1; // next_id += 1;
(id, rng.gen_range(0..=200) as f32 / 2.0) // (id, rng.gen_range(0..=200) as f32 / 2.0)
}) // })
.collect::<Vec<_>>(), // .collect::<Vec<_>>(),
)); // ));
let orientation = *[Orientation::Top, Orientation::Bottom] // let orientation = *[Orientation::Top, Orientation::Bottom]
.choose(&mut rng) // .choose(&mut rng)
.unwrap(); // .unwrap();
let overdraw = rng.gen_range(1..=100) as f32; // let overdraw = rng.gen_range(1..=100) as f32;
let state = view.update(cx, |_, cx| { // let state = view.update(cx, |_, cx| {
ListState::new(elements.borrow().len(), orientation, overdraw, cx, { // ListState::new(elements.borrow().len(), orientation, overdraw, cx, {
let elements = elements.clone(); // let elements = elements.clone();
move |_, ix, _| { // move |_, ix, _| {
let (id, height) = elements.borrow()[ix]; // let (id, height) = elements.borrow()[ix];
TestElement::new(id, height).boxed() // TestElement::new(id, height).boxed()
} // }
}) // })
}); // });
let mut width = rng.gen_range(0..=2000) as f32 / 2.; // let mut width = rng.gen_range(0..=2000) as f32 / 2.;
let mut height = rng.gen_range(0..=2000) as f32 / 2.; // let mut height = rng.gen_range(0..=2000) as f32 / 2.;
log::info!("orientation: {:?}", orientation); // log::info!("orientation: {:?}", orientation);
log::info!("overdraw: {}", overdraw); // log::info!("overdraw: {}", overdraw);
log::info!("elements: {:?}", elements.borrow()); // log::info!("elements: {:?}", elements.borrow());
log::info!("size: ({:?}, {:?})", width, height); // log::info!("size: ({:?}, {:?})", width, height);
log::info!("=================="); // log::info!("==================");
let mut last_logical_scroll_top = None; // let mut last_logical_scroll_top = None;
for _ in 0..operations { // for _ in 0..operations {
match rng.gen_range(0..=100) { // match rng.gen_range(0..=100) {
0..=29 if last_logical_scroll_top.is_some() => { // 0..=29 if last_logical_scroll_top.is_some() => {
let delta = vec2f(0., rng.gen_range(-overdraw..=overdraw)); // let delta = vec2f(0., rng.gen_range(-overdraw..=overdraw));
log::info!( // log::info!(
"Scrolling by {:?}, previous scroll top: {:?}", // "Scrolling by {:?}, previous scroll top: {:?}",
delta, // delta,
last_logical_scroll_top.unwrap() // last_logical_scroll_top.unwrap()
); // );
state.0.borrow_mut().scroll( // state.0.borrow_mut().scroll(
last_logical_scroll_top.as_ref().unwrap(), // last_logical_scroll_top.as_ref().unwrap(),
height, // height,
delta, // delta,
true, // true,
&mut presenter.build_event_context(&mut Default::default(), cx), // &mut presenter.build_event_context(&mut Default::default(), cx),
); // );
} // }
30..=34 => { // 30..=34 => {
width = rng.gen_range(0..=2000) as f32 / 2.; // width = rng.gen_range(0..=2000) as f32 / 2.;
log::info!("changing width: {:?}", width); // log::info!("changing width: {:?}", width);
} // }
35..=54 => { // 35..=54 => {
height = rng.gen_range(0..=1000) as f32 / 2.; // height = rng.gen_range(0..=1000) as f32 / 2.;
log::info!("changing height: {:?}", height); // log::info!("changing height: {:?}", height);
} // }
_ => { // _ => {
let mut elements = elements.borrow_mut(); // let mut elements = elements.borrow_mut();
let end_ix = rng.gen_range(0..=elements.len()); // let end_ix = rng.gen_range(0..=elements.len());
let start_ix = rng.gen_range(0..=end_ix); // let start_ix = rng.gen_range(0..=end_ix);
let new_elements = (0..rng.gen_range(0..10)) // let new_elements = (0..rng.gen_range(0..10))
.map(|_| { // .map(|_| {
let id = next_id; // let id = next_id;
next_id += 1; // next_id += 1;
(id, rng.gen_range(0..=200) as f32 / 2.) // (id, rng.gen_range(0..=200) as f32 / 2.)
}) // })
.collect::<Vec<_>>(); // .collect::<Vec<_>>();
log::info!("splice({:?}, {:?})", start_ix..end_ix, new_elements); // log::info!("splice({:?}, {:?})", start_ix..end_ix, new_elements);
state.splice(start_ix..end_ix, new_elements.len()); // state.splice(start_ix..end_ix, new_elements.len());
elements.splice(start_ix..end_ix, new_elements); // elements.splice(start_ix..end_ix, new_elements);
for (ix, item) in state.0.borrow().items.cursor::<()>().enumerate() { // for (ix, item) in state.0.borrow().items.cursor::<()>().enumerate() {
if let ListItem::Rendered(element) = item { // if let ListItem::Rendered(element) = item {
let (expected_id, _) = elements[ix]; // let (expected_id, _) = elements[ix];
element.with_metadata(|metadata: Option<&usize>| { // element.with_metadata(|metadata: Option<&usize>| {
assert_eq!(*metadata.unwrap(), expected_id); // assert_eq!(*metadata.unwrap(), expected_id);
}); // });
} // }
} // }
} // }
} // }
let mut list = List::new(state.clone()); // let mut list = List::new(state.clone());
let window_size = vec2f(width, height); // let window_size = vec2f(width, height);
let (size, logical_scroll_top) = list.layout( // let (size, logical_scroll_top) = list.layout(
SizeConstraint::new(vec2f(0., 0.), window_size), // SizeConstraint::new(vec2f(0., 0.), window_size),
&mut presenter.build_layout_context(window_size, false, cx), // &mut presenter.build_layout_context(window_size, false, cx),
); // );
assert_eq!(size, window_size); // assert_eq!(size, window_size);
last_logical_scroll_top = Some(logical_scroll_top); // last_logical_scroll_top = Some(logical_scroll_top);
let state = state.0.borrow(); // let state = state.0.borrow();
log::info!("items {:?}", state.items.items(&())); // log::info!("items {:?}", state.items.items(&()));
let scroll_top = state.scroll_top(&logical_scroll_top); // let scroll_top = state.scroll_top(&logical_scroll_top);
let rendered_top = (scroll_top - overdraw).max(0.); // let rendered_top = (scroll_top - overdraw).max(0.);
let rendered_bottom = scroll_top + height + overdraw; // let rendered_bottom = scroll_top + height + overdraw;
let mut item_top = 0.; // let mut item_top = 0.;
log::info!( // log::info!(
"rendered top {:?}, rendered bottom {:?}, scroll top {:?}", // "rendered top {:?}, rendered bottom {:?}, scroll top {:?}",
rendered_top, // rendered_top,
rendered_bottom, // rendered_bottom,
scroll_top, // scroll_top,
); // );
let mut first_rendered_element_top = None; // let mut first_rendered_element_top = None;
let mut last_rendered_element_bottom = None; // let mut last_rendered_element_bottom = None;
assert_eq!(state.items.summary().count, elements.borrow().len()); // assert_eq!(state.items.summary().count, elements.borrow().len());
for (ix, item) in state.items.cursor::<()>().enumerate() { // for (ix, item) in state.items.cursor::<()>().enumerate() {
match item { // match item {
ListItem::Unrendered => { // ListItem::Unrendered => {
let item_bottom = item_top; // let item_bottom = item_top;
assert!(item_bottom <= rendered_top || item_top >= rendered_bottom); // assert!(item_bottom <= rendered_top || item_top >= rendered_bottom);
item_top = item_bottom; // item_top = item_bottom;
} // }
ListItem::Removed(height) => { // ListItem::Removed(height) => {
let (id, expected_height) = elements.borrow()[ix]; // let (id, expected_height) = elements.borrow()[ix];
assert_eq!( // assert_eq!(
*height, expected_height, // *height, expected_height,
"element {} height didn't match", // "element {} height didn't match",
id // id
); // );
let item_bottom = item_top + height; // let item_bottom = item_top + height;
assert!(item_bottom <= rendered_top || item_top >= rendered_bottom); // assert!(item_bottom <= rendered_top || item_top >= rendered_bottom);
item_top = item_bottom; // item_top = item_bottom;
} // }
ListItem::Rendered(element) => { // ListItem::Rendered(element) => {
let (expected_id, expected_height) = elements.borrow()[ix]; // let (expected_id, expected_height) = elements.borrow()[ix];
element.with_metadata(|metadata: Option<&usize>| { // element.with_metadata(|metadata: Option<&usize>| {
assert_eq!(*metadata.unwrap(), expected_id); // assert_eq!(*metadata.unwrap(), expected_id);
}); // });
assert_eq!(element.size().y(), expected_height); // assert_eq!(element.size().y(), expected_height);
let item_bottom = item_top + element.size().y(); // let item_bottom = item_top + element.size().y();
first_rendered_element_top.get_or_insert(item_top); // first_rendered_element_top.get_or_insert(item_top);
last_rendered_element_bottom = Some(item_bottom); // last_rendered_element_bottom = Some(item_bottom);
assert!(item_bottom > rendered_top || item_top < rendered_bottom); // assert!(item_bottom > rendered_top || item_top < rendered_bottom);
item_top = item_bottom; // item_top = item_bottom;
} // }
} // }
} // }
match orientation { // match orientation {
Orientation::Top => { // Orientation::Top => {
if let Some(first_rendered_element_top) = first_rendered_element_top { // if let Some(first_rendered_element_top) = first_rendered_element_top {
assert!(first_rendered_element_top <= scroll_top); // assert!(first_rendered_element_top <= scroll_top);
} // }
} // }
Orientation::Bottom => { // Orientation::Bottom => {
if let Some(last_rendered_element_bottom) = last_rendered_element_bottom { // if let Some(last_rendered_element_bottom) = last_rendered_element_bottom {
assert!(last_rendered_element_bottom >= scroll_top + height); // assert!(last_rendered_element_bottom >= scroll_top + height);
} // }
} // }
} // }
} // }
} }
struct TestView; struct TestView;

View file

@ -233,14 +233,16 @@ impl<Tag, V: View> Element<V> for MouseEventHandler<Tag, V> {
cx: &mut ViewContext<V>, cx: &mut ViewContext<V>,
) -> Self::PaintState { ) -> Self::PaintState {
if self.above { if self.above {
self.child.paint(bounds.origin(), visible_bounds, view, cx); self.child
.paint(scene, bounds.origin(), visible_bounds, view, cx);
cx.paint_layer(None, |cx| { cx.paint_layer(None, |cx| {
self.paint_regions(bounds, visible_bounds, cx); self.paint_regions(scene, bounds, visible_bounds, cx);
}); });
} else { } else {
self.paint_regions(bounds, visible_bounds, cx); self.paint_regions(scene, bounds, visible_bounds, cx);
self.child.paint(bounds.origin(), visible_bounds, view, cx); self.child
.paint(scene, bounds.origin(), visible_bounds, view, cx);
} }
} }

View file

@ -131,7 +131,7 @@ impl<V: View> Element<V> for Overlay<V> {
} else { } else {
constraint constraint
}; };
let size = self.child.layout(constraint, cx); let size = self.child.layout(constraint, view, cx);
(Vector2F::zero(), size) (Vector2F::zero(), size)
} }

View file

@ -7,7 +7,7 @@ use crate::{
geometry::rect::RectF, geometry::rect::RectF,
platform::{CursorStyle, MouseButton}, platform::{CursorStyle, MouseButton},
scene::MouseDrag, scene::MouseDrag,
Axis, Element, ElementBox, ElementStateHandle, MouseRegion, RenderContext, View, Axis, Element, ElementBox, ElementStateHandle, MouseRegion, SceneBuilder, View, ViewContext,
}; };
use super::{ConstrainedBox, Hook}; use super::{ConstrainedBox, Hook};
@ -75,22 +75,22 @@ struct ResizeHandleState {
custom_dimension: Cell<f32>, custom_dimension: Cell<f32>,
} }
pub struct Resizable { pub struct Resizable<V: View> {
side: Side, side: Side,
handle_size: f32, handle_size: f32,
child: ElementBox, child: ElementBox<V>,
state: Rc<ResizeHandleState>, state: Rc<ResizeHandleState>,
_state_handle: ElementStateHandle<Rc<ResizeHandleState>>, _state_handle: ElementStateHandle<Rc<ResizeHandleState>>,
} }
impl Resizable { impl<V: View> Resizable<V> {
pub fn new<Tag: 'static, T: View>( pub fn new<Tag: 'static, T: View>(
child: ElementBox, child: ElementBox<V>,
element_id: usize, element_id: usize,
side: Side, side: Side,
handle_size: f32, handle_size: f32,
initial_size: f32, initial_size: f32,
cx: &mut RenderContext<T>, cx: &mut ViewContext<V>,
) -> Self { ) -> Self {
let state_handle = cx.element_state::<Tag, Rc<ResizeHandleState>>( let state_handle = cx.element_state::<Tag, Rc<ResizeHandleState>>(
element_id, element_id,
@ -132,24 +132,27 @@ impl Resizable {
} }
} }
impl Element for Resizable { impl<V: View> Element<V> for Resizable<V> {
type LayoutState = (); type LayoutState = ();
type PaintState = (); type PaintState = ();
fn layout( fn layout(
&mut self, &mut self,
constraint: crate::SizeConstraint, constraint: crate::SizeConstraint,
cx: &mut crate::LayoutContext, view: &mut V,
cx: &mut ViewContext<V>,
) -> (Vector2F, Self::LayoutState) { ) -> (Vector2F, Self::LayoutState) {
(self.child.layout(constraint, cx), ()) (self.child.layout(constraint, view, cx), ())
} }
fn paint( fn paint(
&mut self, &mut self,
scene: &mut SceneBuilder,
bounds: pathfinder_geometry::rect::RectF, bounds: pathfinder_geometry::rect::RectF,
visible_bounds: pathfinder_geometry::rect::RectF, visible_bounds: pathfinder_geometry::rect::RectF,
_child_size: &mut Self::LayoutState, _child_size: &mut Self::LayoutState,
cx: &mut crate::PaintContext, view: &mut V,
cx: &mut ViewContext<V>,
) -> Self::PaintState { ) -> Self::PaintState {
cx.scene.push_stacking_context(None, None); cx.scene.push_stacking_context(None, None);
@ -186,7 +189,8 @@ impl Element for Resizable {
cx.scene.pop_stacking_context(); cx.scene.pop_stacking_context();
self.child.paint(bounds.origin(), visible_bounds, cx); self.child
.paint(scene, bounds.origin(), visible_bounds, view, cx);
} }
fn rect_for_text_range( fn rect_for_text_range(
@ -196,9 +200,10 @@ impl Element for Resizable {
_visible_bounds: pathfinder_geometry::rect::RectF, _visible_bounds: pathfinder_geometry::rect::RectF,
_layout: &Self::LayoutState, _layout: &Self::LayoutState,
_paint: &Self::PaintState, _paint: &Self::PaintState,
cx: &crate::MeasurementContext, view: &V,
cx: &ViewContext<V>,
) -> Option<pathfinder_geometry::rect::RectF> { ) -> Option<pathfinder_geometry::rect::RectF> {
self.child.rect_for_text_range(range_utf16, cx) self.child.rect_for_text_range(range_utf16, view, cx)
} }
fn debug( fn debug(
@ -206,10 +211,11 @@ impl Element for Resizable {
_bounds: pathfinder_geometry::rect::RectF, _bounds: pathfinder_geometry::rect::RectF,
_layout: &Self::LayoutState, _layout: &Self::LayoutState,
_paint: &Self::PaintState, _paint: &Self::PaintState,
cx: &crate::DebugContext, view: &V,
cx: &ViewContext<V>,
) -> serde_json::Value { ) -> serde_json::Value {
json!({ json!({
"child": self.child.debug(cx), "child": self.child.debug(view, cx),
}) })
} }
} }

View file

@ -3,41 +3,41 @@ use std::ops::Range;
use crate::{ use crate::{
geometry::{rect::RectF, vector::Vector2F}, geometry::{rect::RectF, vector::Vector2F},
json::{self, json, ToJson}, json::{self, json, ToJson},
window::MeasurementContext, Element, ElementBox, SceneBuilder, SizeConstraint, View, ViewContext,
DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint,
}; };
/// Element which renders it's children in a stack on top of each other. /// Element which renders it's children in a stack on top of each other.
/// The first child determines the size of the others. /// The first child determines the size of the others.
#[derive(Default)] #[derive(Default)]
pub struct Stack { pub struct Stack<V: View> {
children: Vec<ElementBox>, children: Vec<ElementBox<V>>,
} }
impl Stack { impl<V: View> Stack<V> {
pub fn new() -> Self { pub fn new() -> Self {
Self::default() Self::default()
} }
} }
impl Element for Stack { impl<V: View> Element<V> for Stack<V> {
type LayoutState = (); type LayoutState = ();
type PaintState = (); type PaintState = ();
fn layout( fn layout(
&mut self, &mut self,
mut constraint: SizeConstraint, mut constraint: SizeConstraint,
cx: &mut LayoutContext, view: &mut V,
cx: &mut ViewContext<V>,
) -> (Vector2F, Self::LayoutState) { ) -> (Vector2F, Self::LayoutState) {
let mut size = constraint.min; let mut size = constraint.min;
let mut children = self.children.iter_mut(); let mut children = self.children.iter_mut();
if let Some(bottom_child) = children.next() { if let Some(bottom_child) = children.next() {
size = bottom_child.layout(constraint, cx); size = bottom_child.layout(constraint, view, cx);
constraint = SizeConstraint::strict(size); constraint = SizeConstraint::strict(size);
} }
for child in children { for child in children {
child.layout(constraint, cx); child.layout(constraint, view, cx);
} }
(size, ()) (size, ())
@ -45,14 +45,16 @@ impl Element for Stack {
fn paint( fn paint(
&mut self, &mut self,
scene: &mut SceneBuilder,
bounds: RectF, bounds: RectF,
visible_bounds: RectF, visible_bounds: RectF,
_: &mut Self::LayoutState, _: &mut Self::LayoutState,
cx: &mut PaintContext, view: &mut V,
cx: &mut ViewContext<V>,
) -> Self::PaintState { ) -> Self::PaintState {
for child in &mut self.children { for child in &mut self.children {
cx.paint_layer(None, |cx| { cx.paint_layer(None, |cx| {
child.paint(bounds.origin(), visible_bounds, cx); child.paint(scene, bounds.origin(), visible_bounds, view, cx);
}); });
} }
} }
@ -64,12 +66,13 @@ impl Element for Stack {
_: RectF, _: RectF,
_: &Self::LayoutState, _: &Self::LayoutState,
_: &Self::PaintState, _: &Self::PaintState,
cx: &MeasurementContext, view: &V,
cx: &ViewContext<V>,
) -> Option<RectF> { ) -> Option<RectF> {
self.children self.children
.iter() .iter()
.rev() .rev()
.find_map(|child| child.rect_for_text_range(range_utf16.clone(), cx)) .find_map(|child| child.rect_for_text_range(range_utf16.clone(), view, cx))
} }
fn debug( fn debug(
@ -77,18 +80,19 @@ impl Element for Stack {
bounds: RectF, bounds: RectF,
_: &Self::LayoutState, _: &Self::LayoutState,
_: &Self::PaintState, _: &Self::PaintState,
cx: &DebugContext, view: &V,
cx: &ViewContext<V>,
) -> json::Value { ) -> json::Value {
json!({ json!({
"type": "Stack", "type": "Stack",
"bounds": bounds.to_json(), "bounds": bounds.to_json(),
"children": self.children.iter().map(|child| child.debug(cx)).collect::<Vec<json::Value>>() "children": self.children.iter().map(|child| child.debug(view, cx)).collect::<Vec<json::Value>>()
}) })
} }
} }
impl Extend<ElementBox> for Stack { impl<V: View> Extend<ElementBox<V>> for Stack<V> {
fn extend<T: IntoIterator<Item = ElementBox>>(&mut self, children: T) { fn extend<T: IntoIterator<Item = ElementBox<V>>>(&mut self, children: T) {
self.children.extend(children) self.children.extend(children)
} }
} }

View file

@ -8,9 +8,7 @@ use crate::{
rect::RectF, rect::RectF,
vector::{vec2f, Vector2F}, vector::{vec2f, Vector2F},
}, },
scene, scene, Element, SceneBuilder, SizeConstraint, View, ViewContext,
window::MeasurementContext,
DebugContext, Element, LayoutContext, PaintContext, SizeConstraint,
}; };
pub struct Svg { pub struct Svg {
@ -32,14 +30,15 @@ impl Svg {
} }
} }
impl Element for Svg { impl<V: View> Element<V> for Svg {
type LayoutState = Option<usvg::Tree>; type LayoutState = Option<usvg::Tree>;
type PaintState = (); type PaintState = ();
fn layout( fn layout(
&mut self, &mut self,
constraint: SizeConstraint, constraint: SizeConstraint,
cx: &mut LayoutContext, view: &mut V,
cx: &mut ViewContext<V>,
) -> (Vector2F, Self::LayoutState) { ) -> (Vector2F, Self::LayoutState) {
match cx.asset_cache.svg(&self.path) { match cx.asset_cache.svg(&self.path) {
Ok(tree) => { Ok(tree) => {
@ -59,13 +58,15 @@ impl Element for Svg {
fn paint( fn paint(
&mut self, &mut self,
scene: &mut SceneBuilder,
bounds: RectF, bounds: RectF,
_visible_bounds: RectF, _visible_bounds: RectF,
svg: &mut Self::LayoutState, svg: &mut Self::LayoutState,
cx: &mut PaintContext, _: &mut V,
_: &mut ViewContext<V>,
) { ) {
if let Some(svg) = svg.clone() { if let Some(svg) = svg.clone() {
cx.scene.push_icon(scene::Icon { scene.push_icon(scene::Icon {
bounds, bounds,
svg, svg,
path: self.path.clone(), path: self.path.clone(),
@ -81,7 +82,8 @@ impl Element for Svg {
_: RectF, _: RectF,
_: &Self::LayoutState, _: &Self::LayoutState,
_: &Self::PaintState, _: &Self::PaintState,
_: &MeasurementContext, _: &V,
_: &ViewContext<V>,
) -> Option<RectF> { ) -> Option<RectF> {
None None
} }
@ -91,7 +93,8 @@ impl Element for Svg {
bounds: RectF, bounds: RectF,
_: &Self::LayoutState, _: &Self::LayoutState,
_: &Self::PaintState, _: &Self::PaintState,
_: &DebugContext, _: &V,
_: &ViewContext<V>,
) -> serde_json::Value { ) -> serde_json::Value {
json!({ json!({
"type": "Svg", "type": "Svg",

View file

@ -7,8 +7,7 @@ use crate::{
}, },
json::{ToJson, Value}, json::{ToJson, Value},
text_layout::{Line, RunStyle, ShapedBoundary}, text_layout::{Line, RunStyle, ShapedBoundary},
window::MeasurementContext, Element, FontCache, SceneBuilder, SizeConstraint, TextLayoutCache, View, ViewContext,
DebugContext, Element, FontCache, LayoutContext, PaintContext, SizeConstraint, TextLayoutCache,
}; };
use log::warn; use log::warn;
use serde_json::json; use serde_json::json;
@ -53,14 +52,15 @@ impl Text {
} }
} }
impl Element for Text { impl<V: View> Element<V> for Text {
type LayoutState = LayoutState; type LayoutState = LayoutState;
type PaintState = (); type PaintState = ();
fn layout( fn layout(
&mut self, &mut self,
constraint: SizeConstraint, constraint: SizeConstraint,
cx: &mut LayoutContext, _: &mut V,
cx: &mut ViewContext<V>,
) -> (Vector2F, Self::LayoutState) { ) -> (Vector2F, Self::LayoutState) {
// Convert the string and highlight ranges into an iterator of highlighted chunks. // Convert the string and highlight ranges into an iterator of highlighted chunks.
@ -99,7 +99,7 @@ impl Element for Text {
chunks, chunks,
&self.style, &self.style,
cx.text_layout_cache, cx.text_layout_cache,
cx.font_cache, &cx.font_cache,
usize::MAX, usize::MAX,
self.text.matches('\n').count() + 1, self.text.matches('\n').count() + 1,
); );
@ -143,10 +143,12 @@ impl Element for Text {
fn paint( fn paint(
&mut self, &mut self,
scene: &mut SceneBuilder,
bounds: RectF, bounds: RectF,
visible_bounds: RectF, visible_bounds: RectF,
layout: &mut Self::LayoutState, layout: &mut Self::LayoutState,
cx: &mut PaintContext, _: &mut V,
cx: &mut ViewContext<V>,
) -> Self::PaintState { ) -> Self::PaintState {
let mut origin = bounds.origin(); let mut origin = bounds.origin();
let empty = Vec::new(); let empty = Vec::new();
@ -163,6 +165,7 @@ impl Element for Text {
if boundaries.intersects(visible_bounds) { if boundaries.intersects(visible_bounds) {
if self.soft_wrap { if self.soft_wrap {
line.paint_wrapped( line.paint_wrapped(
scene,
origin, origin,
visible_bounds, visible_bounds,
layout.line_height, layout.line_height,
@ -170,7 +173,7 @@ impl Element for Text {
cx, cx,
); );
} else { } else {
line.paint(origin, visible_bounds, layout.line_height, cx); line.paint(scene, origin, visible_bounds, layout.line_height, cx);
} }
} }
origin.set_y(boundaries.max_y()); origin.set_y(boundaries.max_y());
@ -184,7 +187,8 @@ impl Element for Text {
_: RectF, _: RectF,
_: &Self::LayoutState, _: &Self::LayoutState,
_: &Self::PaintState, _: &Self::PaintState,
_: &MeasurementContext, _: &V,
_: &ViewContext<V>,
) -> Option<RectF> { ) -> Option<RectF> {
None None
} }
@ -194,7 +198,8 @@ impl Element for Text {
bounds: RectF, bounds: RectF,
_: &Self::LayoutState, _: &Self::LayoutState,
_: &Self::PaintState, _: &Self::PaintState,
_: &DebugContext, _: &V,
_: &ViewContext<V>,
) -> Value { ) -> Value {
json!({ json!({
"type": "Text", "type": "Text",
@ -272,7 +277,7 @@ pub fn layout_highlighted_chunks<'a>(
mod tests { mod tests {
use super::*; use super::*;
use crate::{ use crate::{
elements::Empty, fonts, platform, AppContext, ElementBox, Entity, RenderContext, View, elements::Empty, fonts, platform, AppContext, ElementBox, Entity, View, ViewContext,
}; };
#[crate::test(self)] #[crate::test(self)]
@ -305,7 +310,7 @@ mod tests {
"TestView" "TestView"
} }
fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox { fn render(&mut self, _: &mut ViewContext<Self>) -> ElementBox<Self> {
Empty::new().boxed() Empty::new().boxed()
} }
} }

View file

@ -6,9 +6,7 @@ use crate::{
fonts::TextStyle, fonts::TextStyle,
geometry::{rect::RectF, vector::Vector2F}, geometry::{rect::RectF, vector::Vector2F},
json::json, json::json,
window::MeasurementContext, Action, Axis, ElementStateHandle, SceneBuilder, SizeConstraint, Task, View, ViewContext,
Action, Axis, ElementStateHandle, LayoutContext, PaintContext, RenderContext, SizeConstraint,
Task, View,
}; };
use serde::Deserialize; use serde::Deserialize;
use std::{ use std::{
@ -20,9 +18,9 @@ use std::{
const DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(500); const DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(500);
pub struct Tooltip { pub struct Tooltip<V: View> {
child: ElementBox, child: ElementBox<V>,
tooltip: Option<ElementBox>, tooltip: Option<ElementBox<V>>,
_state: ElementStateHandle<Rc<TooltipState>>, _state: ElementStateHandle<Rc<TooltipState>>,
} }
@ -50,18 +48,19 @@ pub struct KeystrokeStyle {
text: TextStyle, text: TextStyle,
} }
impl Tooltip { impl<V: View> Tooltip<V> {
pub fn new<Tag: 'static, T: View>( pub fn new<Tag: 'static, T: View>(
id: usize, id: usize,
text: String, text: String,
action: Option<Box<dyn Action>>, action: Option<Box<dyn Action>>,
style: TooltipStyle, style: TooltipStyle,
child: ElementBox, child: ElementBox<V>,
cx: &mut RenderContext<T>, view: &mut V,
cx: &mut ViewContext<V>,
) -> Self { ) -> Self {
struct ElementState<Tag>(Tag); struct ElementState<Tag>(Tag);
struct MouseEventHandlerState<Tag>(Tag); struct MouseEventHandlerState<Tag>(Tag);
let focused_view_id = cx.focused_view_id(cx.window_id); let focused_view_id = cx.focused_view_id();
let state_handle = cx.default_element_state::<ElementState<Tag>, Rc<TooltipState>>(id); let state_handle = cx.default_element_state::<ElementState<Tag>, Rc<TooltipState>>(id);
let state = state_handle.read(cx).clone(); let state = state_handle.read(cx).clone();
@ -94,35 +93,36 @@ impl Tooltip {
} else { } else {
None None
}; };
let child = MouseEventHandler::<MouseEventHandlerState<Tag>>::new(id, cx, |_, _| child) let child =
.on_hover(move |e, cx| { MouseEventHandler::<MouseEventHandlerState<Tag>>::new(id, view, cx, |_, _| child)
let position = e.position; .on_hover(move |e, cx| {
let window_id = cx.window_id(); let position = e.position;
if let Some(view_id) = cx.view_id() { let window_id = cx.window_id();
if e.started { if let Some(view_id) = cx.view_id() {
if !state.visible.get() { if e.started {
state.position.set(position); if !state.visible.get() {
state.position.set(position);
let mut debounce = state.debounce.borrow_mut(); let mut debounce = state.debounce.borrow_mut();
if debounce.is_none() { if debounce.is_none() {
*debounce = Some(cx.spawn({ *debounce = Some(cx.spawn({
let state = state.clone(); let state = state.clone();
|mut cx| async move { |mut cx| async move {
cx.background().timer(DEBOUNCE_TIMEOUT).await; cx.background().timer(DEBOUNCE_TIMEOUT).await;
state.visible.set(true); state.visible.set(true);
cx.update(|cx| cx.notify_view(window_id, view_id)); cx.update(|cx| cx.notify_view(window_id, view_id));
} }
})); }));
}
} }
} else {
state.visible.set(false);
state.debounce.take();
cx.notify();
} }
} else {
state.visible.set(false);
state.debounce.take();
cx.notify();
} }
} })
}) .boxed();
.boxed();
Self { Self {
child, child,
tooltip, tooltip,
@ -168,32 +168,40 @@ impl Tooltip {
} }
} }
impl Element for Tooltip { impl<V: View> Element<V> for Tooltip<V> {
type LayoutState = (); type LayoutState = ();
type PaintState = (); type PaintState = ();
fn layout( fn layout(
&mut self, &mut self,
constraint: SizeConstraint, constraint: SizeConstraint,
cx: &mut LayoutContext, view: &mut V,
cx: &mut ViewContext<V>,
) -> (Vector2F, Self::LayoutState) { ) -> (Vector2F, Self::LayoutState) {
let size = self.child.layout(constraint, cx); let size = self.child.layout(constraint, view, cx);
if let Some(tooltip) = self.tooltip.as_mut() { if let Some(tooltip) = self.tooltip.as_mut() {
tooltip.layout(SizeConstraint::new(Vector2F::zero(), cx.window_size), cx); tooltip.layout(
SizeConstraint::new(Vector2F::zero(), cx.window_size),
view,
cx,
);
} }
(size, ()) (size, ())
} }
fn paint( fn paint(
&mut self, &mut self,
scene: &mut SceneBuilder,
bounds: RectF, bounds: RectF,
visible_bounds: RectF, visible_bounds: RectF,
_: &mut Self::LayoutState, _: &mut Self::LayoutState,
cx: &mut PaintContext, view: &mut V,
cx: &mut ViewContext<V>,
) { ) {
self.child.paint(bounds.origin(), visible_bounds, cx); self.child
.paint(scene, bounds.origin(), visible_bounds, view, cx);
if let Some(tooltip) = self.tooltip.as_mut() { if let Some(tooltip) = self.tooltip.as_mut() {
tooltip.paint(bounds.origin(), visible_bounds, cx); tooltip.paint(scene, bounds.origin(), visible_bounds, view, cx);
} }
} }
@ -204,9 +212,10 @@ impl Element for Tooltip {
_: RectF, _: RectF,
_: &Self::LayoutState, _: &Self::LayoutState,
_: &Self::PaintState, _: &Self::PaintState,
cx: &MeasurementContext, view: &V,
cx: &ViewContext<V>,
) -> Option<RectF> { ) -> Option<RectF> {
self.child.rect_for_text_range(range, cx) self.child.rect_for_text_range(range, view, cx)
} }
fn debug( fn debug(
@ -214,11 +223,12 @@ impl Element for Tooltip {
_: RectF, _: RectF,
_: &Self::LayoutState, _: &Self::LayoutState,
_: &Self::PaintState, _: &Self::PaintState,
cx: &crate::DebugContext, view: &V,
cx: &ViewContext<V>,
) -> serde_json::Value { ) -> serde_json::Value {
json!({ json!({
"child": self.child.debug(cx), "child": self.child.debug(view, cx),
"tooltip": self.tooltip.as_ref().map(|t| t.debug(cx)), "tooltip": self.tooltip.as_ref().map(|t| t.debug(view, cx)),
}) })
} }
} }

View file

@ -104,7 +104,7 @@ impl<V: View> UniformList<V> {
mut delta: Vector2F, mut delta: Vector2F,
precise: bool, precise: bool,
scroll_max: f32, scroll_max: f32,
cx: &mut EventContext, cx: &mut ViewContext<V>,
) -> bool { ) -> bool {
if !precise { if !precise {
delta *= 20.; delta *= 20.;

View file

@ -19,7 +19,7 @@ pub use scene::{Border, CursorRegion, MouseRegion, MouseRegionId, Quad, Scene, S
pub mod text_layout; pub mod text_layout;
pub use text_layout::TextLayoutCache; pub use text_layout::TextLayoutCache;
mod util; mod util;
pub use elements::{Element, ElementBox, ElementRc}; pub use elements::{Element, ElementBox};
pub mod executor; pub mod executor;
pub use executor::Task; pub use executor::Task;
pub mod color; pub mod color;
@ -27,10 +27,7 @@ pub mod json;
pub mod keymap_matcher; pub mod keymap_matcher;
pub mod platform; pub mod platform;
pub use gpui_macros::test; pub use gpui_macros::test;
pub use window::{ pub use window::{Axis, SizeConstraint, Vector2FExt};
Axis, DebugContext, EventContext, LayoutContext, MeasurementContext, PaintContext,
SizeConstraint, Vector2FExt,
};
pub use anyhow; pub use anyhow;
pub use serde_json; pub use serde_json;

View file

@ -5,7 +5,7 @@ use collections::HashMap;
use pathfinder_geometry::rect::RectF; use pathfinder_geometry::rect::RectF;
use smallvec::SmallVec; use smallvec::SmallVec;
use crate::{platform::MouseButton, EventContext}; use crate::{platform::MouseButton, window::WindowContext, View, ViewContext};
use super::{ use super::{
mouse_event::{ mouse_event::{
@ -60,82 +60,92 @@ impl MouseRegion {
} }
} }
pub fn on_down( pub fn on_down<V, F>(mut self, button: MouseButton, handler: F) -> Self
mut self, where
button: MouseButton, V: View,
handler: impl Fn(MouseDown, &mut EventContext) + 'static, F: Fn(MouseDown, &mut V, &mut ViewContext<V>) + 'static,
) -> Self { {
self.handlers = self.handlers.on_down(button, handler); self.handlers = self.handlers.on_down(button, handler);
self self
} }
pub fn on_up( pub fn on_up<V, F>(mut self, button: MouseButton, handler: F) -> Self
mut self, where
button: MouseButton, V: View,
handler: impl Fn(MouseUp, &mut EventContext) + 'static, F: Fn(MouseUp, &mut V, &mut ViewContext<V>) + 'static,
) -> Self { {
self.handlers = self.handlers.on_up(button, handler); self.handlers = self.handlers.on_up(button, handler);
self self
} }
pub fn on_click( pub fn on_click<V, F>(mut self, button: MouseButton, handler: F) -> Self
mut self, where
button: MouseButton, V: View,
handler: impl Fn(MouseClick, &mut EventContext) + 'static, F: Fn(MouseClick, &mut V, &mut ViewContext<V>) + 'static,
) -> Self { {
self.handlers = self.handlers.on_click(button, handler); self.handlers = self.handlers.on_click(button, handler);
self self
} }
pub fn on_down_out( pub fn on_down_out<V, F>(mut self, button: MouseButton, handler: F) -> Self
mut self, where
button: MouseButton, V: View,
handler: impl Fn(MouseDownOut, &mut EventContext) + 'static, F: Fn(MouseDownOut, &mut V, &mut ViewContext<V>) + 'static,
) -> Self { {
self.handlers = self.handlers.on_down_out(button, handler); self.handlers = self.handlers.on_down_out(button, handler);
self self
} }
pub fn on_up_out( pub fn on_up_out<V, F>(mut self, button: MouseButton, handler: F) -> Self
mut self, where
button: MouseButton, V: View,
handler: impl Fn(MouseUpOut, &mut EventContext) + 'static, F: Fn(MouseUpOut, &mut V, &mut ViewContext<V>) + 'static,
) -> Self { {
self.handlers = self.handlers.on_up_out(button, handler); self.handlers = self.handlers.on_up_out(button, handler);
self self
} }
pub fn on_drag( pub fn on_drag<V, F>(mut self, button: MouseButton, handler: F) -> Self
mut self, where
button: MouseButton, V: View,
handler: impl Fn(MouseDrag, &mut EventContext) + 'static, F: Fn(MouseDrag, &mut V, &mut ViewContext<V>) + 'static,
) -> Self { {
self.handlers = self.handlers.on_drag(button, handler); self.handlers = self.handlers.on_drag(button, handler);
self self
} }
pub fn on_hover(mut self, handler: impl Fn(MouseHover, &mut EventContext) + 'static) -> Self { pub fn on_hover<V, F>(mut self, handler: F) -> Self
where
V: View,
F: Fn(&mut V, &mut ViewContext<V>) + 'static,
{
self.handlers = self.handlers.on_hover(handler); self.handlers = self.handlers.on_hover(handler);
self self
} }
pub fn on_move(mut self, handler: impl Fn(MouseMove, &mut EventContext) + 'static) -> Self { pub fn on_move<V, F>(mut self, handler: F) -> Self
where
V: View,
F: Fn(&mut V, &mut ViewContext<V>) + 'static,
{
self.handlers = self.handlers.on_move(handler); self.handlers = self.handlers.on_move(handler);
self self
} }
pub fn on_move_out( pub fn on_move_out<V, F>(mut self, handler: F) -> Self
mut self, where
handler: impl Fn(MouseMoveOut, &mut EventContext) + 'static, V: View,
) -> Self { F: Fn(&mut V, &mut ViewContext<V>) + 'static,
{
self.handlers = self.handlers.on_move_out(handler); self.handlers = self.handlers.on_move_out(handler);
self self
} }
pub fn on_scroll( pub fn on_scroll<V, F>(mut self, handler: F) -> Self
mut self, where
handler: impl Fn(MouseScrollWheel, &mut EventContext) + 'static, V: View,
) -> Self { F: Fn(&mut V, &mut ViewContext<V>) + 'static,
{
self.handlers = self.handlers.on_scroll(handler); self.handlers = self.handlers.on_scroll(handler);
self self
} }
@ -186,7 +196,7 @@ impl MouseRegionId {
} }
} }
pub type HandlerCallback = Rc<dyn Fn(MouseEvent, &mut EventContext)>; pub type HandlerCallback = Rc<dyn Fn(MouseEvent, &mut WindowContext)>;
#[derive(Clone, PartialEq, Eq, Hash)] #[derive(Clone, PartialEq, Eq, Hash)]
pub struct HandlerKey { pub struct HandlerKey {
@ -283,7 +293,11 @@ impl HandlerSet {
} }
} }
pub fn on_move(mut self, handler: impl Fn(MouseMove, &mut EventContext) + 'static) -> Self { pub fn on_move<V, F>(mut self, handler: F) -> Self
where
V: View,
F: Fn(MouseMove, &mut V, &mut ViewContext<Self>) + 'static,
{
self.insert(MouseEvent::move_disc(), None, self.insert(MouseEvent::move_disc(), None,
Rc::new(move |region_event, cx| { Rc::new(move |region_event, cx| {
if let MouseEvent::Move(e) = region_event { if let MouseEvent::Move(e) = region_event {
@ -297,10 +311,11 @@ impl HandlerSet {
self self
} }
pub fn on_move_out( pub fn on_move_out<V, F>(mut self, handler: F) -> Self
mut self, where
handler: impl Fn(MouseMoveOut, &mut EventContext) + 'static, V: View,
) -> Self { F: Fn(MouseMoveOut, &mut V, &mut ViewContext<V>) + 'static,
{
self.insert(MouseEvent::move_out_disc(), None, self.insert(MouseEvent::move_out_disc(), None,
Rc::new(move |region_event, cx| { Rc::new(move |region_event, cx| {
if let MouseEvent::MoveOut(e) = region_event { if let MouseEvent::MoveOut(e) = region_event {
@ -314,11 +329,11 @@ impl HandlerSet {
self self
} }
pub fn on_down( pub fn on_down<V, F>(mut self, button: MouseButton, handler: F) -> Self
mut self, where
button: MouseButton, V: View,
handler: impl Fn(MouseDown, &mut EventContext) + 'static, F: Fn(MouseDown, &mut V, &mut ViewContext<V>) + 'static,
) -> Self { {
self.insert(MouseEvent::down_disc(), Some(button), self.insert(MouseEvent::down_disc(), Some(button),
Rc::new(move |region_event, cx| { Rc::new(move |region_event, cx| {
if let MouseEvent::Down(e) = region_event { if let MouseEvent::Down(e) = region_event {
@ -332,11 +347,11 @@ impl HandlerSet {
self self
} }
pub fn on_up( pub fn on_up<V, F>(mut self, button: MouseButton, handler: F) -> Self
mut self, where
button: MouseButton, V: View,
handler: impl Fn(MouseUp, &mut EventContext) + 'static, F: Fn(MouseUp, &mut V, &mut ViewContext<V>) + 'static,
) -> Self { {
self.insert(MouseEvent::up_disc(), Some(button), self.insert(MouseEvent::up_disc(), Some(button),
Rc::new(move |region_event, cx| { Rc::new(move |region_event, cx| {
if let MouseEvent::Up(e) = region_event { if let MouseEvent::Up(e) = region_event {
@ -350,11 +365,11 @@ impl HandlerSet {
self self
} }
pub fn on_click( pub fn on_click<V, F>(mut self, button: MouseButton, handler: F) -> Self
mut self, where
button: MouseButton, V: View,
handler: impl Fn(MouseClick, &mut EventContext) + 'static, F: Fn(MouseClick, &mut V, &mut ViewContext<V>) + 'static,
) -> Self { {
self.insert(MouseEvent::click_disc(), Some(button), self.insert(MouseEvent::click_disc(), Some(button),
Rc::new(move |region_event, cx| { Rc::new(move |region_event, cx| {
if let MouseEvent::Click(e) = region_event { if let MouseEvent::Click(e) = region_event {
@ -368,11 +383,11 @@ impl HandlerSet {
self self
} }
pub fn on_down_out( pub fn on_down_out<V, F>(mut self, button: MouseButton, handler: F) -> Self
mut self, where
button: MouseButton, V: View,
handler: impl Fn(MouseDownOut, &mut EventContext) + 'static, F: Fn(MouseDownOut, &mut V, &mut ViewContext<V>) + 'static,
) -> Self { {
self.insert(MouseEvent::down_out_disc(), Some(button), self.insert(MouseEvent::down_out_disc(), Some(button),
Rc::new(move |region_event, cx| { Rc::new(move |region_event, cx| {
if let MouseEvent::DownOut(e) = region_event { if let MouseEvent::DownOut(e) = region_event {
@ -386,11 +401,11 @@ impl HandlerSet {
self self
} }
pub fn on_up_out( pub fn on_up_out<V, F>(mut self, button: MouseButton, handler: F) -> Self
mut self, where
button: MouseButton, V: View,
handler: impl Fn(MouseUpOut, &mut EventContext) + 'static, F: Fn(MouseUpOut, &mut V, &mut ViewContext<V>) + 'static,
) -> Self { {
self.insert(MouseEvent::up_out_disc(), Some(button), self.insert(MouseEvent::up_out_disc(), Some(button),
Rc::new(move |region_event, cx| { Rc::new(move |region_event, cx| {
if let MouseEvent::UpOut(e) = region_event { if let MouseEvent::UpOut(e) = region_event {
@ -404,11 +419,11 @@ impl HandlerSet {
self self
} }
pub fn on_drag( pub fn on_drag<V, F>(mut self, button: MouseButton, handler: F) -> Self
mut self, where
button: MouseButton, V: View,
handler: impl Fn(MouseDrag, &mut EventContext) + 'static, F: Fn(MouseDrag, &mut V, &mut ViewContext<V>) + 'static,
) -> Self { {
self.insert(MouseEvent::drag_disc(), Some(button), self.insert(MouseEvent::drag_disc(), Some(button),
Rc::new(move |region_event, cx| { Rc::new(move |region_event, cx| {
if let MouseEvent::Drag(e) = region_event { if let MouseEvent::Drag(e) = region_event {
@ -422,7 +437,11 @@ impl HandlerSet {
self self
} }
pub fn on_hover(mut self, handler: impl Fn(MouseHover, &mut EventContext) + 'static) -> Self { pub fn on_hover<V, F>(mut self, handler: F) -> Self
where
V: View,
F: Fn(MouseHover, &mut V, &mut ViewContext<V>) + 'static,
{
self.insert(MouseEvent::hover_disc(), None, self.insert(MouseEvent::hover_disc(), None,
Rc::new(move |region_event, cx| { Rc::new(move |region_event, cx| {
if let MouseEvent::Hover(e) = region_event { if let MouseEvent::Hover(e) = region_event {
@ -436,10 +455,11 @@ impl HandlerSet {
self self
} }
pub fn on_scroll( pub fn on_scroll<V, F>(mut self, handler: F) -> Self
mut self, where
handler: impl Fn(MouseScrollWheel, &mut EventContext) + 'static, V: View,
) -> Self { F: Fn(MouseScrollWheel, &mut V, &mut ViewContext<V>) + 'static,
{
self.insert(MouseEvent::scroll_wheel_disc(), None, self.insert(MouseEvent::scroll_wheel_disc(), None,
Rc::new(move |region_event, cx| { Rc::new(move |region_event, cx| {
if let MouseEvent::ScrollWheel(e) = region_event { if let MouseEvent::ScrollWheel(e) = region_event {

View file

@ -19,8 +19,8 @@ use crate::{
platform, platform,
platform::Platform, platform::Platform,
util::CwdBacktrace, util::CwdBacktrace,
AppContext, Element, ElementBox, Entity, FontCache, Handle, RenderContext, Subscription, AppContext, Element, ElementBox, Entity, FontCache, Handle, Subscription, TestAppContext, View,
TestAppContext, View, ViewContext,
}; };
#[cfg(test)] #[cfg(test)]
@ -240,7 +240,7 @@ impl View for EmptyView {
"empty view" "empty view"
} }
fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox { fn render(&mut self, _: &mut ViewContext<Self>) -> ElementBox<Self> {
Element::boxed(Empty::new()) Element::boxed(Empty::new())
} }
} }

View file

@ -9,7 +9,7 @@ use crate::{
platform::FontSystem, platform::FontSystem,
scene, scene,
window::WindowContext, window::WindowContext,
AppContext, PaintContext, SceneBuilder, SceneBuilder,
}; };
use ordered_float::OrderedFloat; use ordered_float::OrderedFloat;
use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard}; use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};
@ -376,11 +376,12 @@ impl Line {
pub fn paint_wrapped( pub fn paint_wrapped(
&self, &self,
scene: &SceneBuilder,
origin: Vector2F, origin: Vector2F,
visible_bounds: RectF, visible_bounds: RectF,
line_height: f32, line_height: f32,
boundaries: impl IntoIterator<Item = ShapedBoundary>, boundaries: impl IntoIterator<Item = ShapedBoundary>,
cx: &mut PaintContext, cx: &mut WindowContext,
) { ) {
let padding_top = (line_height - self.layout.ascent - self.layout.descent) / 2.; let padding_top = (line_height - self.layout.ascent - self.layout.descent) / 2.;
let baseline_origin = vec2f(0., padding_top + self.layout.ascent); let baseline_origin = vec2f(0., padding_top + self.layout.ascent);
@ -419,14 +420,14 @@ impl Line {
); );
if glyph_bounds.intersects(visible_bounds) { if glyph_bounds.intersects(visible_bounds) {
if glyph.is_emoji { if glyph.is_emoji {
cx.scene.push_image_glyph(scene::ImageGlyph { scene.push_image_glyph(scene::ImageGlyph {
font_id: run.font_id, font_id: run.font_id,
font_size: self.layout.font_size, font_size: self.layout.font_size,
id: glyph.id, id: glyph.id,
origin: glyph_bounds.origin() + baseline_origin, origin: glyph_bounds.origin() + baseline_origin,
}); });
} else { } else {
cx.scene.push_glyph(scene::Glyph { scene.push_glyph(scene::Glyph {
font_id: run.font_id, font_id: run.font_id,
font_size: self.layout.font_size, font_size: self.layout.font_size,
id: glyph.id, id: glyph.id,

View file

@ -1,13 +1,13 @@
use serde::Deserialize; use serde::Deserialize;
use crate::{ use crate::{
actions, elements::*, impl_actions, platform::MouseButton, AppContext, Entity, RenderContext, actions, elements::*, impl_actions, platform::MouseButton, AppContext, Entity, View,
View, ViewContext, WeakViewHandle, ViewContext, WeakViewHandle,
}; };
pub struct Select { pub struct Select {
handle: WeakViewHandle<Self>, handle: WeakViewHandle<Self>,
render_item: Box<dyn Fn(usize, ItemType, bool, &AppContext) -> ElementBox>, render_item: Box<dyn Fn(usize, ItemType, bool, &AppContext) -> ElementBox<Self>>,
selected_item_ix: usize, selected_item_ix: usize,
item_count: usize, item_count: usize,
is_open: bool, is_open: bool,
@ -41,7 +41,7 @@ pub fn init(cx: &mut AppContext) {
} }
impl Select { impl Select {
pub fn new<F: 'static + Fn(usize, ItemType, bool, &AppContext) -> ElementBox>( pub fn new<F: 'static + Fn(usize, ItemType, bool, &AppContext) -> ElementBox<Self>>(
item_count: usize, item_count: usize,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
render_item: F, render_item: F,
@ -92,7 +92,7 @@ impl View for Select {
"Select" "Select"
} }
fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox { fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox<Self> {
if self.item_count == 0 { if self.item_count == 0 {
return Empty::new().boxed(); return Empty::new().boxed();
} }
@ -106,16 +106,21 @@ impl View for Select {
Default::default() Default::default()
}; };
let mut result = Flex::column().with_child( let mut result = Flex::column().with_child(
MouseEventHandler::<Header>::new(self.handle.id(), cx, |mouse_state, cx| { MouseEventHandler::<Header>::new(
Container::new((self.render_item)( self.handle.id(),
self.selected_item_ix, self,
ItemType::Header, cx,
mouse_state.hovered(), |mouse_state, this, cx| {
cx, Container::new((self.render_item)(
)) self.selected_item_ix,
.with_style(style.header) ItemType::Header,
.boxed() mouse_state.hovered(),
}) cx,
))
.with_style(style.header)
.boxed()
},
)
.on_click(MouseButton::Left, move |_, cx| { .on_click(MouseButton::Left, move |_, cx| {
cx.dispatch_action(ToggleSelect) cx.dispatch_action(ToggleSelect)
}) })
@ -134,18 +139,23 @@ impl View for Select {
let selected_item_ix = this.selected_item_ix; let selected_item_ix = this.selected_item_ix;
range.end = range.end.min(this.item_count); range.end = range.end.min(this.item_count);
items.extend(range.map(|ix| { items.extend(range.map(|ix| {
MouseEventHandler::<Item>::new(ix, cx, |mouse_state, cx| { MouseEventHandler::<Item>::new(
(this.render_item)( ix,
ix, self,
if ix == selected_item_ix { cx,
ItemType::Selected |mouse_state, this, cx| {
} else { (this.render_item)(
ItemType::Unselected ix,
}, if ix == selected_item_ix {
mouse_state.hovered(), ItemType::Selected
cx, } else {
) ItemType::Unselected
}) },
mouse_state.hovered(),
cx,
)
},
)
.on_click(MouseButton::Left, move |_, cx| { .on_click(MouseButton::Left, move |_, cx| {
cx.dispatch_action(SelectItem(ix)) cx.dispatch_action(SelectItem(ix))
}) })