#import "modules/std.sx"; #import "modules/math"; #import "ui/types.sx"; #import "ui/events.sx"; GesturePhase :: enum { possible; began; changed; ended; cancelled; failed; } // --- TapGesture --- TapValue :: struct { location: Point; count: s32; } TapGesture :: struct { count: s32; on_tap: ?Closure(); phase: GesturePhase; tap_count: s32; start_position: Point; TAP_THRESHOLD :f32: 10.0; handle_event :: (self: *TapGesture, event: *Event, frame: Frame) -> bool { if event.* == { case .mouse_down: (d) { if frame.contains(d.position) { self.phase = .began; self.start_position = d.position; return true; } } case .mouse_moved: (d) { if self.phase == .began { if self.start_position.distance(d.position) > TapGesture.TAP_THRESHOLD { self.phase = .failed; } } } case .mouse_up: (d) { if self.phase == .began { if frame.contains(d.position) { self.tap_count += 1; if self.tap_count >= self.count { if handler := self.on_tap { handler(); } self.tap_count = 0; } } } self.phase = .possible; return true; } } false; } } // --- DragGesture --- DragValue :: struct { location: Point; start_location: Point; translation: Point; } DragGesture :: struct { min_distance: f32; on_changed: ?Closure(DragValue); on_ended: ?Closure(DragValue); phase: GesturePhase; start_location: Point; current_location: Point; make_value :: (self: *DragGesture) -> DragValue { DragValue.{ location = self.current_location, start_location = self.start_location, translation = self.current_location.sub(self.start_location) }; } handle_event :: (self: *DragGesture, event: *Event, frame: Frame) -> bool { if event.* == { case .mouse_down: (d) { if frame.contains(d.position) { self.phase = .possible; self.start_location = d.position; self.current_location = d.position; return true; } } case .mouse_moved: (d) { if self.phase == .possible { self.current_location = d.position; if self.start_location.distance(d.position) >= self.min_distance { self.phase = .began; if handler := self.on_changed { handler(self.make_value()); } } return true; } if self.phase == .began or self.phase == .changed { self.current_location = d.position; self.phase = .changed; if handler := self.on_changed { handler(self.make_value()); } return true; } } case .mouse_up: (d) { if self.phase == .began or self.phase == .changed { self.current_location = d.position; self.phase = .ended; if handler := self.on_ended { handler(self.make_value()); } self.phase = .possible; return true; } self.phase = .possible; } } false; } }