T13a Lists: ListItem, List, SelectableList, VirtualList, InfiniteList, GroupedList, SortableList, SwipeableListItem (review pending: codex 401)
This commit is contained in:
23 files changed
+1820
-14
No files matched your search
@@ -0,0 +1,91 @@
|
||||
use anyhow::Result;
|
||||
use gpui::{AsyncApp, Pixels, Point, WindowHandle};
|
||||
|
||||
use crate::{capture::number, shell::Gallery};
|
||||
|
||||
/// A scroll's phase, as AppKit numbers them.
|
||||
pub const BEGAN: i64 = 1;
|
||||
pub const CHANGED: i64 = 2;
|
||||
pub const ENDED: i64 = 4;
|
||||
|
||||
pub fn swipe(
|
||||
window: WindowHandle<Gallery>,
|
||||
at: Point<Pixels>,
|
||||
across: f32,
|
||||
phase: i64,
|
||||
cx: &mut AsyncApp,
|
||||
) -> Result<()> {
|
||||
let (height, number) = window.update(cx, |_, window, _| {
|
||||
(window.viewport_size().height, number(window))
|
||||
})?;
|
||||
post_scroll(
|
||||
f64::from(at.x),
|
||||
f64::from(height - at.y),
|
||||
across,
|
||||
phase,
|
||||
number?,
|
||||
)
|
||||
}
|
||||
|
||||
/// Sends a real trackpad scroll to the window, sideways by `across` points, with its phase. Quartz scrolls carry no window, so AppKit reads their location as window points and the window takes them directly.
|
||||
#[cfg(target_os = "macos")]
|
||||
fn post_scroll(x: f64, y: f64, across: f32, phase: i64, number: u32) -> Result<()> {
|
||||
use cocoa::{
|
||||
appkit::NSApp,
|
||||
base::{id, nil},
|
||||
foundation::NSRect,
|
||||
};
|
||||
use objc::{class, msg_send, sel, sel_impl};
|
||||
type Event = *mut std::ffi::c_void;
|
||||
#[repr(C)]
|
||||
struct Spot {
|
||||
x: f64,
|
||||
y: f64,
|
||||
}
|
||||
unsafe extern "C" {
|
||||
fn CGEventCreateScrollWheelEvent2(
|
||||
source: *const std::ffi::c_void,
|
||||
units: u32,
|
||||
count: u32,
|
||||
wheel1: i32,
|
||||
wheel2: i32,
|
||||
wheel3: i32,
|
||||
) -> Event;
|
||||
fn CGEventSetIntegerValueField(event: Event, field: u32, value: i64);
|
||||
fn CGEventSetLocation(event: Event, at: Spot);
|
||||
fn CFRelease(object: *const std::ffi::c_void);
|
||||
}
|
||||
const PIXELS: u32 = 0;
|
||||
const CONTINUOUS: u32 = 88;
|
||||
const PHASE: u32 = 99;
|
||||
unsafe {
|
||||
let window: id = msg_send![NSApp(), windowWithWindowNumber: i64::from(number)];
|
||||
anyhow::ensure!(window != nil, "no window numbered {number}");
|
||||
let screens: id = msg_send![class!(NSScreen), screens];
|
||||
let primary: id = msg_send![screens, objectAtIndex: 0usize];
|
||||
let frame: NSRect = msg_send![primary, frame];
|
||||
let event = CGEventCreateScrollWheelEvent2(
|
||||
std::ptr::null(),
|
||||
PIXELS,
|
||||
2,
|
||||
0,
|
||||
across.round() as i32,
|
||||
0,
|
||||
);
|
||||
anyhow::ensure!(!event.is_null(), "Quartz refused a scroll event");
|
||||
CGEventSetLocation(
|
||||
event,
|
||||
Spot {
|
||||
x,
|
||||
y: frame.size.height - y,
|
||||
},
|
||||
);
|
||||
CGEventSetIntegerValueField(event, CONTINUOUS, 1);
|
||||
CGEventSetIntegerValueField(event, PHASE, phase);
|
||||
let scroll: id = msg_send![class!(NSEvent), eventWithCGEvent: event];
|
||||
CFRelease(event);
|
||||
anyhow::ensure!(scroll != nil, "AppKit refused a scroll event");
|
||||
let _: () = msg_send![window, sendEvent: scroll];
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Reference in new issue
Block a user