use std::fmt::Debug;
use kas::event::PressSource;
use kas::prelude::*;
#[handler(handle=noauto)]
#[derive(Clone, Debug, Default, Widget)]
pub struct DragHandle {
#[widget_core]
core: CoreData,
track: Rect,
press_source: Option<event::PressSource>,
press_offset: Coord,
}
impl DragHandle {
pub fn new() -> Self {
DragHandle {
core: Default::default(),
track: Default::default(),
press_source: None,
press_offset: Coord::ZERO,
}
}
pub fn set_size_and_offset(&mut self, size: Size, offset: Coord) -> TkAction {
self.core.rect.size = size;
self.set_offset(offset).1
}
#[inline]
pub fn track(&self) -> Rect {
self.track
}
#[inline]
pub fn offset(&self) -> Coord {
self.core.rect.pos - self.track.pos
}
#[inline]
pub fn max_offset(&self) -> Coord {
Coord::from(self.track.size) - Coord::from(self.core.rect.size)
}
pub fn set_offset(&mut self, offset: Coord) -> (Coord, TkAction) {
let offset = offset.clamp(Coord::ZERO, self.max_offset());
let handle_pos = self.track.pos + offset;
if handle_pos != self.core.rect.pos {
self.core.rect.pos = handle_pos;
(offset, TkAction::Redraw)
} else {
(offset, TkAction::None)
}
}
pub fn handle_press_on_track(
&mut self,
mgr: &mut Manager,
source: PressSource,
coord: Coord,
) -> Coord {
if !self.grab_press(mgr, source, coord) {
return self.offset();
}
self.press_offset = Coord::from(self.core.rect.size / 2) + self.track.pos;
let (offset, action) = self.set_offset(coord - self.press_offset);
debug_assert!(action == TkAction::Redraw);
mgr.send_action(action);
offset
}
fn grab_press(&mut self, mgr: &mut Manager, source: PressSource, coord: Coord) -> bool {
let cur = Some(event::CursorIcon::Grabbing);
if mgr.request_grab(self.id(), source, coord, event::GrabMode::Grab, cur) {
self.press_source = Some(source);
true
} else {
false
}
}
}
impl Layout for DragHandle {
fn size_rules(&mut self, _: &mut dyn SizeHandle, _: AxisInfo) -> SizeRules {
SizeRules::EMPTY
}
fn set_rect(&mut self, rect: Rect, _: AlignHints) {
self.track = rect;
}
fn draw(&self, _: &mut dyn DrawHandle, _: &event::ManagerState, _: bool) {}
}
impl event::Handler for DragHandle {
type Msg = Coord;
fn handle(&mut self, mgr: &mut Manager, event: Event) -> Response<Self::Msg> {
match event {
Event::PressStart { source, coord, .. } => {
if !self.grab_press(mgr, source, coord) {
return Response::None;
}
self.press_offset = coord - self.offset();
Response::None
}
Event::PressMove { source, coord, .. } if Some(source) == self.press_source => {
let offset = coord - self.press_offset;
let (offset, action) = self.set_offset(offset);
if action == TkAction::None {
Response::None
} else {
mgr.send_action(action);
Response::Msg(offset)
}
}
Event::PressEnd { source, .. } if Some(source) == self.press_source => {
self.press_source = None;
Response::None
}
event => Response::Unhandled(event),
}
}
}