From 3cbcb5d3a65f2c03e61d19168bdac7ce98f2f741 Mon Sep 17 00:00:00 2001 From: Shafkath Shuhan Date: Tue, 10 Jan 2023 22:43:22 -0500 Subject: [PATCH 1/2] wip --- helix-term/src/compositor.rs | 66 ++++++++++++++++++++++++++++++++- helix-term/src/ui/completion.rs | 4 ++ helix-term/src/ui/popup.rs | 14 ++++++- 3 files changed, 81 insertions(+), 3 deletions(-) diff --git a/helix-term/src/compositor.rs b/helix-term/src/compositor.rs index 9dad36209c62..5eca945dc036 100644 --- a/helix-term/src/compositor.rs +++ b/helix-term/src/compositor.rs @@ -71,6 +71,15 @@ pub trait Component: Any + AnyComponent { fn id(&self) -> Option<&'static str> { None } + + fn area(&self, viewport: Rect) -> Option { + None + } + + /// If multiple components share the same level, then only the most recent one is rendered. + fn level(&self) -> Option { + None + } } pub struct Compositor { @@ -137,7 +146,31 @@ impl Compositor { // propagate events through the layers until we either find a layer that consumes it or we // run out of layers (event bubbling) - for layer in self.layers.iter_mut().rev() { + for layer in self.layers.iter_mut().rev().filter(|component| { + // Returns true if either doesn't have a level, or level hasn't been seen before. + component + .level() + .filter(|level| { + self.layers + .iter() + .rev() + .find(|other| { + other + .level() + .filter(|other_level| other_level == level) + .is_some() + }) + .and_then(|other| { + Some( + other + .area(self.size())? + .intersects(component.area(self.size())?), + ) + }) + .is_none() + }) + .is_none() + }) { match layer.handle_event(event, cx) { EventResult::Consumed(Some(callback)) => { callbacks.push(callback); @@ -163,7 +196,36 @@ impl Compositor { } pub fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) { - for layer in &mut self.layers { + let layers = self + .layers + .iter_mut() + .rev() + .filter(|component| { + // Returns true if either doesn't have a level, or level hasn't been seen before. + component + .level() + .filter(|level| { + self.layers + .iter() + .rev() + .find(|other| { + other + .level() + .filter(|other_level| other_level == level) + .is_some() + }) + .and_then(|other| { + Some((other.area(self.size())?, component.area(self.size())?)) + }) + .filter(|(other_area, component_area)| { + other_area.intersects(*component_area) + }) + .is_none() + }) + .is_none() + }) + .rev(); + for layer in layers { layer.render(area, surface, cx); } } diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs index 11d7886a37d6..d925afcdddd5 100644 --- a/helix-term/src/ui/completion.rs +++ b/helix-term/src/ui/completion.rs @@ -484,4 +484,8 @@ impl Component for Completion { markdown_doc.render(area, surface, cx); } } + + fn level(&self) -> Option { + Some(0) + } } diff --git a/helix-term/src/ui/popup.rs b/helix-term/src/ui/popup.rs index 62a6785a4ef2..e7d9a8c0e99d 100644 --- a/helix-term/src/ui/popup.rs +++ b/helix-term/src/ui/popup.rs @@ -23,6 +23,8 @@ pub struct Popup { ignore_escape_key: bool, id: &'static str, has_scrollbar: bool, + level: Option, + area: Rect, } impl Popup { @@ -39,9 +41,15 @@ impl Popup { ignore_escape_key: false, id, has_scrollbar: true, + level: None, + area: Rect::default(), } } + pub fn set_level(mut self, level: usize) { + self.level = Some(level); + } + pub fn position(mut self, pos: Option) -> Self { self.position = pos; self @@ -231,7 +239,7 @@ impl Component for Popup { // clip to viewport let area = viewport.intersection(Rect::new(rel_x, rel_y, self.size.0, self.size.1)); - + self.area = area; // clear area let background = cx.editor.theme.get("ui.popup"); surface.clear_with(area, background); @@ -274,6 +282,10 @@ impl Component for Popup { } } + fn area(&self, _viewport: Rect) -> Option { + Some(self.area) + } + fn id(&self) -> Option<&'static str> { Some(self.id) } From 122b4c52dcd98def4e8d52913428f274b0932712 Mon Sep 17 00:00:00 2001 From: Shafkath Shuhan Date: Tue, 10 Jan 2023 23:07:09 -0500 Subject: [PATCH 2/2] wip --- helix-term/src/compositor.rs | 80 +++++++++++++++--------------------- helix-term/src/ui/popup.rs | 2 +- 2 files changed, 33 insertions(+), 49 deletions(-) diff --git a/helix-term/src/compositor.rs b/helix-term/src/compositor.rs index 5eca945dc036..4a1a05748cc5 100644 --- a/helix-term/src/compositor.rs +++ b/helix-term/src/compositor.rs @@ -72,7 +72,7 @@ pub trait Component: Any + AnyComponent { None } - fn area(&self, viewport: Rect) -> Option { + fn area(&self) -> Option { None } @@ -146,31 +146,24 @@ impl Compositor { // propagate events through the layers until we either find a layer that consumes it or we // run out of layers (event bubbling) - for layer in self.layers.iter_mut().rev().filter(|component| { - // Returns true if either doesn't have a level, or level hasn't been seen before. - component - .level() - .filter(|level| { - self.layers - .iter() - .rev() - .find(|other| { - other - .level() - .filter(|other_level| other_level == level) - .is_some() - }) - .and_then(|other| { - Some( - other - .area(self.size())? - .intersects(component.area(self.size())?), - ) - }) - .is_none() - }) - .is_none() - }) { + let components_by_level: Vec<(usize, Rect)> = self + .layers + .iter() + .filter_map(|component| Some((component.level()?, component.area()?))) + .collect(); + let layers = self.layers.iter_mut().rev().filter(|component| { + match (component.level(), component.area()) { + (Some(level), Some(area)) => components_by_level + .iter() + .rev() + .find(|(other_level, other_area)| { + *other_level == level && other_area.intersects(area) + }) + .is_none(), + _ => false, + } + }); + for layer in layers { match layer.handle_event(event, cx) { EventResult::Consumed(Some(callback)) => { callbacks.push(callback); @@ -196,33 +189,24 @@ impl Compositor { } pub fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) { + let components_by_level: Vec<(usize, Rect)> = self + .layers + .iter() + .filter_map(|component| Some((component.level()?, component.area()?))) + .collect(); let layers = self .layers .iter_mut() .rev() - .filter(|component| { - // Returns true if either doesn't have a level, or level hasn't been seen before. - component - .level() - .filter(|level| { - self.layers - .iter() - .rev() - .find(|other| { - other - .level() - .filter(|other_level| other_level == level) - .is_some() - }) - .and_then(|other| { - Some((other.area(self.size())?, component.area(self.size())?)) - }) - .filter(|(other_area, component_area)| { - other_area.intersects(*component_area) - }) - .is_none() + .filter(|component| match (component.level(), component.area()) { + (Some(level), Some(area)) => components_by_level + .iter() + .rev() + .find(|(other_level, other_area)| { + *other_level == level && other_area.intersects(area) }) - .is_none() + .is_none(), + _ => false, }) .rev(); for layer in layers { diff --git a/helix-term/src/ui/popup.rs b/helix-term/src/ui/popup.rs index e7d9a8c0e99d..75936bc865fc 100644 --- a/helix-term/src/ui/popup.rs +++ b/helix-term/src/ui/popup.rs @@ -282,7 +282,7 @@ impl Component for Popup { } } - fn area(&self, _viewport: Rect) -> Option { + fn area(&self) -> Option { Some(self.area) }