@@ -1,35 +1,12 @@
use crate::{
- AnyElement, BorrowWindow, Bounds, Element, ElementFocus, ElementId, ElementInteraction,
+ point, AnyElement, BorrowWindow, Bounds, Element, ElementFocus, ElementId, ElementInteraction,
FocusDisabled, FocusEnabled, FocusHandle, FocusListeners, Focusable, GlobalElementId,
GroupBounds, InteractiveElementState, IntoAnyElement, LayoutId, Overflow, ParentElement,
Pixels, Point, SharedString, StatefulInteraction, StatefulInteractive, StatelessInteraction,
StatelessInteractive, Style, StyleRefinement, Styled, ViewContext,
};
-use parking_lot::Mutex;
use refineable::Refineable;
use smallvec::SmallVec;
-use std::sync::Arc;
-
-#[derive(Default, Clone)]
-pub struct ScrollState(Arc<Mutex<Point<Pixels>>>);
-
-impl ScrollState {
- pub fn x(&self) -> Pixels {
- self.0.lock().x
- }
-
- pub fn set_x(&self, value: Pixels) {
- self.0.lock().x = value;
- }
-
- pub fn y(&self) -> Pixels {
- self.0.lock().y
- }
-
- pub fn set_y(&self, value: Pixels) {
- self.0.lock().y = value;
- }
-}
pub struct Div<
V: 'static + Send + Sync,
@@ -104,28 +81,6 @@ where
self
}
- pub fn overflow_scroll(mut self, _scroll_state: ScrollState) -> Self {
- // todo!("impl scrolling")
- // self.scroll_state = Some(scroll_state);
- self.base_style.overflow.x = Some(Overflow::Scroll);
- self.base_style.overflow.y = Some(Overflow::Scroll);
- self
- }
-
- pub fn overflow_x_scroll(mut self, _scroll_state: ScrollState) -> Self {
- // todo!("impl scrolling")
- // self.scroll_state = Some(scroll_state);
- self.base_style.overflow.x = Some(Overflow::Scroll);
- self
- }
-
- pub fn overflow_y_scroll(mut self, _scroll_state: ScrollState) -> Self {
- // todo!("impl scrolling")
- // self.scroll_state = Some(scroll_state);
- self.base_style.overflow.y = Some(Overflow::Scroll);
- self
- }
-
fn with_element_id<R>(
&mut self,
cx: &mut ViewContext<V>,
@@ -179,6 +134,22 @@ where
base_style: self.base_style,
}
}
+
+ pub fn overflow_scroll(mut self) -> Self {
+ self.base_style.overflow.x = Some(Overflow::Scroll);
+ self.base_style.overflow.y = Some(Overflow::Scroll);
+ self
+ }
+
+ pub fn overflow_x_scroll(mut self) -> Self {
+ self.base_style.overflow.x = Some(Overflow::Scroll);
+ self
+ }
+
+ pub fn overflow_y_scroll(mut self) -> Self {
+ self.base_style.overflow.y = Some(Overflow::Scroll);
+ self
+ }
}
impl<V> Div<V, StatelessInteraction<V>, FocusDisabled>
@@ -225,6 +196,7 @@ where
pub struct DivState {
interactive: InteractiveElementState,
focus_handle: Option<FocusHandle>,
+ child_layout_ids: SmallVec<[LayoutId; 4]>,
}
impl<V, I, F> Element for Div<V, I, F>
@@ -274,7 +246,8 @@ where
.children
.iter_mut()
.map(|child| child.layout(view_state, cx))
- .collect::<Vec<_>>();
+ .collect::<SmallVec<_>>();
+ element_state.child_layout_ids = layout_ids.clone();
cx.request_layout(&style, layout_ids)
})
})
@@ -295,21 +268,38 @@ where
let style = this.compute_style(bounds, element_state, cx);
let z_index = style.z_index.unwrap_or(0);
- // Paint background and event handlers.
+ let mut child_min = point(Pixels::MAX, Pixels::MAX);
+ let mut child_max = Point::default();
+
+ let content_size = if element_state.child_layout_ids.is_empty() {
+ bounds.size
+ } else {
+ for child_layout_id in &element_state.child_layout_ids {
+ let child_bounds = cx.layout_bounds(*child_layout_id);
+ child_min = child_min.min(&child_bounds.origin);
+ child_max = child_min.max(&child_bounds.lower_right());
+ }
+ (child_max - child_min).into()
+ };
+
cx.stack(z_index, |cx| {
cx.stack(0, |cx| {
style.paint(bounds, cx);
-
this.focus.paint(bounds, cx);
- this.interaction
- .paint(bounds, &element_state.interactive, cx);
+ this.interaction.paint(
+ bounds,
+ content_size,
+ style.overflow,
+ &mut element_state.interactive,
+ cx,
+ );
});
-
cx.stack(1, |cx| {
style.apply_text_style(cx, |cx| {
style.apply_overflow(bounds, cx, |cx| {
+ let scroll_offset = element_state.interactive.scroll_offset();
for child in &mut this.children {
- child.paint(view_state, None, cx);
+ child.paint(view_state, scroll_offset, cx);
}
})
})
@@ -205,6 +205,20 @@ where
}
}
+impl<T> Sub for Size<T>
+where
+ T: Sub<Output = T> + Clone + Default + Debug,
+{
+ type Output = Size<T>;
+
+ fn sub(self, rhs: Self) -> Self::Output {
+ Size {
+ width: self.width - rhs.width,
+ height: self.height - rhs.height,
+ }
+ }
+}
+
impl<T, Rhs> Mul<Rhs> for Size<T>
where
T: Mul<Rhs, Output = Rhs> + Clone + Default + Debug,
@@ -242,6 +256,15 @@ where
}
}
+impl<T: Clone + Default + Debug> From<Point<T>> for Size<T> {
+ fn from(point: Point<T>) -> Self {
+ Self {
+ width: point.x,
+ height: point.y,
+ }
+ }
+}
+
impl From<Size<Pixels>> for Size<GlobalPixels> {
fn from(size: Size<Pixels>) -> Self {
Size {
@@ -679,6 +702,8 @@ impl MulAssign<f32> for Pixels {
}
impl Pixels {
+ pub const MAX: Pixels = Pixels(f32::MAX);
+
pub fn round(&self) -> Self {
Self(self.0.round())
}
@@ -1,7 +1,7 @@
use crate::{
- point, Action, AppContext, BorrowWindow, Bounds, DispatchContext, DispatchPhase, Element,
- ElementId, FocusHandle, KeyMatch, Keystroke, Modifiers, Pixels, Point, SharedString, Style,
- StyleRefinement, ViewContext,
+ point, px, Action, AppContext, BorrowWindow, Bounds, DispatchContext, DispatchPhase, Element,
+ ElementId, FocusHandle, KeyMatch, Keystroke, Modifiers, Overflow, Pixels, Point, SharedString,
+ Size, Style, StyleRefinement, ViewContext,
};
use collections::HashMap;
use derive_more::{Deref, DerefMut};
@@ -375,7 +375,9 @@ pub trait ElementInteraction<V: 'static + Send + Sync>: 'static + Send + Sync {
fn paint(
&mut self,
bounds: Bounds<Pixels>,
- element_state: &InteractiveElementState,
+ content_size: Size<Pixels>,
+ overflow: Point<Overflow>,
+ element_state: &mut InteractiveElementState,
cx: &mut ViewContext<V>,
) {
let stateless = self.as_stateless();
@@ -468,6 +470,34 @@ pub trait ElementInteraction<V: 'static + Send + Sync>: 'static + Send + Sync {
}
});
}
+
+ if overflow.x == Overflow::Scroll || overflow.y == Overflow::Scroll {
+ let scroll_offset = element_state
+ .scroll_offset
+ .get_or_insert_with(Arc::default)
+ .clone();
+ let line_height = cx.line_height();
+ let scroll_max = content_size - bounds.size;
+
+ cx.on_mouse_event(move |_, event: &ScrollWheelEvent, _, cx| {
+ if bounds.contains_point(&event.position) {
+ let mut scroll_offset = scroll_offset.lock();
+ let delta = event.delta.pixel_delta(line_height);
+
+ if overflow.x == Overflow::Scroll {
+ scroll_offset.x =
+ (scroll_offset.x - delta.x).clamp(px(0.), scroll_max.width);
+ }
+
+ if overflow.y == Overflow::Scroll {
+ scroll_offset.y =
+ (scroll_offset.y - delta.y).clamp(px(0.), scroll_max.height);
+ }
+
+ cx.notify();
+ }
+ });
+ }
}
}
}
@@ -609,6 +639,15 @@ impl ActiveState {
pub struct InteractiveElementState {
active_state: Arc<Mutex<ActiveState>>,
pending_click: Arc<Mutex<Option<MouseDownEvent>>>,
+ scroll_offset: Option<Arc<Mutex<Point<Pixels>>>>,
+}
+
+impl InteractiveElementState {
+ pub fn scroll_offset(&self) -> Option<Point<Pixels>> {
+ self.scroll_offset
+ .as_ref()
+ .map(|offset| offset.lock().clone())
+ }
}
impl<V> Default for StatelessInteraction<V> {