diff options
| author | Gabriel Schneider <[email protected]> | 2026-08-10 17:23:18 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-08-11 09:58:59 -0300 |
| commit | a797a1ab2f648e773f7a1b28d12bf9441b9f13f4 (patch) | |
| tree | 45db37a3d190425b3ca2453d46c57d2af27cfc93 /test/macos_e2e.swift | |
| parent | eb11ab331b4e13e2b9e5a673a4c012d22fdd1d9c (diff) | |
| download | pardes-a797a1ab2f648e773f7a1b28d12bf9441b9f13f4.tar.gz pardes-a797a1ab2f648e773f7a1b28d12bf9441b9f13f4.zip | |
macos: pixel attachments, live theming, and a signed app
The AppKit shell now draws what the core renders, follows the theme without a
relaunch, and builds into something you can hand to someone.
- Pixel attachments. Surface.images was dropped on the floor here, so a PDF
pane showed nothing at all: native_images is now set, pardes_image_s carries
the geometry the core already clipped, and PardesView keeps one CGImage per
(serial, page, revision) so scrolling costs a draw and not a decode. Image
panes get real pixels instead of the petscii fallback.
- Themes take hold live. pardes_tick never advanced the chrome animation, so
every tagline kept the previous theme's colours until the next launch and
the 16 ms re-pump spun for the rest of the session. pardes_theme_bg retires
the hand-agreed #121212 and drives the window background and the titlebar
appearance; a theme with no background of its own now gets a transparent
window over an NSVisualEffectView.
- The cell snaps to whole DEVICE pixels rather than whole points. Monaco
advances 8.4014pt at 14, so ceiling to 9 spaced every column 7.1% wider than
the face was drawn for.
- The dial is one notch per 10 degrees instead of 20, and a release keeps
turning in proportion to how hard it was thrown -- ramping up from zero at
the floor, so a slow twist coasts not a little but not at all.
- A file dropped on the grid is a click plus Look, so it opens beside the pane
it was dropped on. No drop concept was added to the core.
- The titlebar follows the focused pane: proxy icon, filename, and the dirty
dot. File.saved_revision is the watermark that last one needed.
- Config (SPC f c) prints the resolved startup config path.
- build.zig assembles, signs and packages the bundle itself; build-app.sh is
gone. -Dmacos-identity= takes a Developer ID, macos-dmg makes the image, and
the icon is Glenda.
Diffstat (limited to 'test/macos_e2e.swift')
| -rw-r--r-- | test/macos_e2e.swift | 33 |
1 files changed, 33 insertions, 0 deletions
diff --git a/test/macos_e2e.swift b/test/macos_e2e.swift index ba0c48f0..42bc8229 100644 --- a/test/macos_e2e.swift +++ b/test/macos_e2e.swift @@ -609,12 +609,45 @@ private final class Driver: PardesViewDelegate { view.click(Trackpad.forceClickButton, at: cell) pump() + // `rotate <degrees> [gap_ms]`. The optional gap is a real sleep BEFORE + // the event, and it is the only way a script can say how FAST the dial + // is being turned: libpardes measures the release speed off the + // monotonic clock between events, so back-to-back script calls read as + // an impossibly hard flick. Pace them and a slow twist is genuinely + // slow — which is the half of the momentum contract worth asserting, + // because "no fling" is not something a fling test can show. case "rotate": let view = try live() let degrees = try double(args, 0, "rotate degrees") + if args.count > 1 { + Thread.sleep(forTimeInterval: try double(args, 1, "rotate gap_ms") / 1000) + } view.rotate(degrees: CGFloat(degrees)) pump() + // The fingers coming off. Its own command because the fling is decided + // by the RELEASE SPEED, and a script that could only turn the dial + // could never throw it — NSEvent phases have no public constructor, so + // this entry point is the only way the momentum path is reachable at + // all. The coast is then spent by the pump, at one fixed step per tick. + case "rotate_end": + let view = try live() + view.rotateEnd() + pump() + + // `drop <path> <col> <row>`: a file dropped ON the grid at that cell. + // Same reason as the two above — `NSDraggingInfo` is a protocol with a + // dozen members and no public conformer, so the entry point below the + // event is the only honest way in. What it must prove is the WHERE: a + // drop is a click plus Look, so the document lands beside the pane + // pointed at rather than beside whichever one had focus. + case "drop": + let view = try live() + let path = try token(args, 0, "drop path") + let cell = try gridPoint(args, 1, "drop") + view.drop([path], at: cell) + pump() + case "scroll": let view = try live() let rows = try double(args, 0, "scroll rows") |
