@@ -2,8 +2,8 @@ use std::{any::Any, f32::INFINITY};
use crate::{
json::{self, ToJson, Value},
- Axis, DebugContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext,
- SizeConstraint, Vector2FExt,
+ Axis, DebugContext, Element, ElementBox, ElementStateContext, ElementStateHandle, Event,
+ EventContext, LayoutContext, PaintContext, SizeConstraint, Vector2FExt,
};
use pathfinder_geometry::{
rect::RectF,
@@ -11,9 +11,15 @@ use pathfinder_geometry::{
};
use serde_json::json;
+#[derive(Default)]
+struct ScrollState {
+ scroll_position: f32,
+}
+
pub struct Flex {
axis: Axis,
children: Vec<ElementBox>,
+ scroll_state: Option<ElementStateHandle<ScrollState>>,
}
impl Flex {
@@ -21,6 +27,7 @@ impl Flex {
Self {
axis,
children: Default::default(),
+ scroll_state: None,
}
}
@@ -32,6 +39,15 @@ impl Flex {
Self::new(Axis::Vertical)
}
+ pub fn scrollable<Tag, C>(mut self, element_id: usize, cx: &mut C) -> Self
+ where
+ Tag: 'static,
+ C: ElementStateContext,
+ {
+ self.scroll_state = Some(cx.element_state::<Tag, ScrollState>(element_id));
+ self
+ }
+
fn layout_flex_children(
&mut self,
layout_expanded: bool,
@@ -167,6 +183,13 @@ impl Element for Flex {
size.set_y(constraint.max.y());
}
+ if let Some(scroll_state) = self.scroll_state.as_ref() {
+ scroll_state.update(cx, |scroll_state, _| {
+ scroll_state.scroll_position =
+ scroll_state.scroll_position.min(-remaining_space).max(0.);
+ });
+ }
+
(size, remaining_space)
}
@@ -181,7 +204,16 @@ impl Element for Flex {
if overflowing {
cx.scene.push_layer(Some(bounds));
}
+
let mut child_origin = bounds.origin();
+ if let Some(scroll_state) = self.scroll_state.as_ref() {
+ let scroll_position = scroll_state.read(cx).scroll_position;
+ match self.axis {
+ Axis::Horizontal => child_origin.set_x(child_origin.x() - scroll_position),
+ Axis::Vertical => child_origin.set_y(child_origin.y() - scroll_position),
+ }
+ }
+
for child in &mut self.children {
if *remaining_space > 0. {
if let Some(metadata) = child.metadata::<FlexParentData>() {
@@ -208,8 +240,8 @@ impl Element for Flex {
fn dispatch_event(
&mut self,
event: &Event,
- _: RectF,
- _: &mut Self::LayoutState,
+ bounds: RectF,
+ remaining_space: &mut Self::LayoutState,
_: &mut Self::PaintState,
cx: &mut EventContext,
) -> bool {
@@ -217,6 +249,41 @@ impl Element for Flex {
for child in &mut self.children {
handled = child.dispatch_event(event, cx) || handled;
}
+ if !handled {
+ if let &Event::ScrollWheel {
+ position,
+ delta,
+ precise,
+ } = event
+ {
+ if *remaining_space < 0. && bounds.contains_point(position) {
+ if let Some(scroll_state) = self.scroll_state.as_ref() {
+ scroll_state.update(cx, |scroll_state, cx| {
+ dbg!(precise, delta);
+
+ let mut delta = match self.axis {
+ Axis::Horizontal => {
+ if delta.x() != 0. {
+ delta.x()
+ } else {
+ delta.y()
+ }
+ }
+ Axis::Vertical => delta.y(),
+ };
+ if !precise {
+ delta *= 20.;
+ }
+
+ scroll_state.scroll_position -= delta;
+
+ handled = true;
+ cx.notify();
+ });
+ }
+ }
+ }
+ }
handled
}
@@ -633,7 +633,7 @@ impl Pane {
enum Tabs {}
let pane = cx.handle();
let tabs = MouseEventHandler::new::<Tabs, _, _>(0, cx, |mouse_state, cx| {
- let mut row = Flex::row();
+ let mut row = Flex::row().scrollable::<Tabs, _>(1, cx);
for (ix, item) in self.items.iter().enumerate() {
let is_active = ix == self.active_item_index;