use std::cell::Cell;
use std::rc::Rc;
use crate::{
App, DrawCtx, Event, EventResult, Framebuffer, GfxCtx, Rect, Size, TouchDeviceId, TouchId,
Widget,
};
struct GestureCounter {
bounds: Rect,
count: Rc<Cell<usize>>,
children: Vec<Box<dyn Widget>>,
}
impl GestureCounter {
fn new(count: Rc<Cell<usize>>) -> Self {
Self {
bounds: Rect::default(),
count,
children: Vec::new(),
}
}
}
impl Widget for GestureCounter {
fn bounds(&self) -> Rect {
self.bounds
}
fn set_bounds(&mut self, b: Rect) {
self.bounds = b;
}
fn children(&self) -> &[Box<dyn Widget>] {
&self.children
}
fn children_mut(&mut self) -> &mut Vec<Box<dyn Widget>> {
&mut self.children
}
fn layout(&mut self, available: Size) -> Size {
available
}
fn paint(&mut self, _ctx: &mut dyn DrawCtx) {}
fn on_event(&mut self, event: &Event) -> EventResult {
match event {
Event::MultiTouch { .. } => {
self.count.set(self.count.get() + 1);
EventResult::Consumed
}
_ => EventResult::Ignored,
}
}
}
struct TwoPane {
bounds: Rect,
children: Vec<Box<dyn Widget>>,
}
impl Widget for TwoPane {
fn bounds(&self) -> Rect {
self.bounds
}
fn set_bounds(&mut self, b: Rect) {
self.bounds = b;
}
fn children(&self) -> &[Box<dyn Widget>] {
&self.children
}
fn children_mut(&mut self) -> &mut Vec<Box<dyn Widget>> {
&mut self.children
}
fn layout(&mut self, available: Size) -> Size {
self.bounds = Rect::new(0.0, 0.0, available.width, available.height);
self.children[0].set_bounds(Rect::new(0.0, 0.0, 150.0, available.height));
self.children[1].set_bounds(Rect::new(250.0, 0.0, 150.0, available.height));
available
}
fn paint(&mut self, _ctx: &mut dyn DrawCtx) {}
fn on_event(&mut self, _event: &Event) -> EventResult {
EventResult::Ignored
}
}
const DEV: TouchDeviceId = TouchDeviceId(0);
const VIEWPORT: Size = Size {
width: 400.0,
height: 200.0,
};
fn app_with_two_panes() -> (App, Rc<Cell<usize>>, Rc<Cell<usize>>) {
let left = Rc::new(Cell::new(0));
let right = Rc::new(Cell::new(0));
let root = TwoPane {
bounds: Rect::default(),
children: vec![
Box::new(GestureCounter::new(Rc::clone(&left))),
Box::new(GestureCounter::new(Rc::clone(&right))),
],
};
let mut app = App::new(Box::new(root));
app.layout(VIEWPORT);
(app, left, right)
}
fn paint(app: &mut App) {
let mut fb = Framebuffer::new(VIEWPORT.width as u32, VIEWPORT.height as u32);
let mut ctx = GfxCtx::new(&mut fb);
app.paint(&mut ctx);
}
fn two_fingers_at(app: &mut App, cx_screen: f64, y_screen: f64) {
app.on_touch_start(DEV, TouchId(0), cx_screen - 20.0, y_screen, None);
app.on_touch_start(DEV, TouchId(1), cx_screen + 20.0, y_screen, None);
}
fn move_two_fingers_to(app: &mut App, cx_screen: f64, y_screen: f64) {
app.on_touch_move(DEV, TouchId(0), cx_screen - 20.0, y_screen, None);
app.on_touch_move(DEV, TouchId(1), cx_screen + 20.0, y_screen, None);
}
#[test]
fn gesture_over_left_pane_delivers_only_to_left() {
let (mut app, left, right) = app_with_two_panes();
two_fingers_at(&mut app, 75.0, 100.0);
paint(&mut app);
assert_eq!(left.get(), 1, "left pane must receive the gesture");
assert_eq!(right.get(), 0, "right pane must NOT react (issue 1 + 2)");
assert!(
crate::current_multi_touch().is_some(),
"the display-only thread-local must stay published"
);
move_two_fingers_to(&mut app, 75.0, 110.0);
paint(&mut app);
assert_eq!(left.get(), 2);
assert_eq!(right.get(), 0);
}
#[test]
fn capture_holds_when_centroid_drifts_over_other_pane() {
let (mut app, left, right) = app_with_two_panes();
two_fingers_at(&mut app, 75.0, 100.0);
paint(&mut app);
assert_eq!(left.get(), 1);
move_two_fingers_to(&mut app, 325.0, 100.0);
paint(&mut app);
assert_eq!(left.get(), 2, "captured left pane keeps receiving");
assert_eq!(
right.get(),
0,
"the right pane must never receive a gesture it didn't start"
);
}
#[test]
fn gesture_over_dead_space_delivers_to_neither() {
let (mut app, left, right) = app_with_two_panes();
two_fingers_at(&mut app, 200.0, 100.0);
paint(&mut app);
assert_eq!(left.get(), 0);
assert_eq!(right.get(), 0);
move_two_fingers_to(&mut app, 75.0, 100.0);
paint(&mut app);
assert_eq!(
left.get(),
0,
"no capture means no delivery for this gesture"
);
assert_eq!(right.get(), 0);
}
#[test]
fn mark_subtree_dirty_traverses_gesture_counter_leaves() {
let mut root = TwoPane {
bounds: Rect::default(),
children: vec![
Box::new(GestureCounter::new(Rc::new(Cell::new(0)))),
Box::new(GestureCounter::new(Rc::new(Cell::new(0)))),
],
};
crate::widget::mark_subtree_dirty(&mut root);
}