use ribir_core::prelude::*;
#[derive(Copy, Clone)]
pub enum PointerSelectData {
Start(Point),
Move { from: Point, to: Point },
End { from: Point, to: Point },
}
impl PointerSelectData {
pub fn endpoints(&self) -> (Point, Point) {
match self {
PointerSelectData::Start(p) => (*p, *p),
PointerSelectData::Move { from, to } | PointerSelectData::End { from, to } => (*from, *to),
}
}
}
pub type PointerSelectEvent = CustomEvent<PointerSelectData>;
#[declare]
pub struct PointerSelectRegion {}
fn notify_select_changed(wid: WidgetId, e: PointerSelectData, wnd: &Window) {
wnd.bubble_custom_event(wid, e);
}
impl<'c> ComposeChild<'c> for PointerSelectRegion {
type Child = Widget<'c>;
fn compose_child(_: impl StateWriter<Value = Self>, child: Self::Child) -> Widget<'c> {
fn_widget! {
let mut child = FatObj::new(child);
let grab_handle = Stateful::new(None);
let from = Stateful::new(None);
@(child) {
on_pointer_down: move |e| {
if e.mouse_buttons() == MouseButtons::PRIMARY {
let pos = e.position();
*$write(from) = Some(pos);
*$write(grab_handle) = Some(GrabPointer::grab(e.current_target(), &e.window()));
notify_select_changed(e.current_target(), PointerSelectData::Start(pos), &e.window());
}
},
on_pointer_move: move |e| {
let from = *$read(from);
if let Some(from) = from
&& $read(grab_handle).is_some()
{
notify_select_changed(
e.current_target(),
PointerSelectData::Move { from, to: e.position() },
&e.window()
);
}
},
on_pointer_up: move |e| {
let from = $write(from).take();
if $write(grab_handle).take().is_some()
&& let Some(from) = from
{
notify_select_changed(
e.current_target(),
PointerSelectData::End { from, to: e.position() },
&e.window()
);
}
},
}
}
.into_widget()
}
}