Checkpoint
This commit is contained in:
@@ -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> {
|
||||
|
||||
@@ -457,6 +457,14 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||
self.window.rem_size
|
||||
}
|
||||
|
||||
pub fn line_height(&self) -> Pixels {
|
||||
let rem_size = self.rem_size();
|
||||
let text_style = self.text_style();
|
||||
text_style
|
||||
.line_height
|
||||
.to_pixels(text_style.font_size.into(), rem_size)
|
||||
}
|
||||
|
||||
pub fn stop_propagation(&mut self) {
|
||||
self.window.propagate = false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user