summaryrefslogtreecommitdiff
path: root/src/gui/gui.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-30 14:12:51 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:17 -0300
commitb546b578baadbd8fdd15b42988ad4d66c9c8ff21 (patch)
treebbbcaa94d63b0b695f09f2d389ca287377880d9a /src/gui/gui.zig
parent3f6733c805d873a7af6a6064ace0cf5916f481da (diff)
downloadpardes-b546b578baadbd8fdd15b42988ad4d66c9c8ff21.tar.gz
pardes-b546b578baadbd8fdd15b42988ad4d66c9c8ff21.zip
A program that tracks the mouse gets its clicks, drags and moves over its grid, in the format it chose; Shift keeps pardes's select, execute and look, and chrome is never the program's
Presses and releases under 1000, drags with a button down under 1002, every move once per cell under 1003, X10 presses under 9, in raw terminal input only. A press the program took keeps its drag and release, reported clamped to the grid's edge wherever the pointer goes. The press also makes the pane the active one. docs/tags.md says so. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/gui/gui.zig')
-rw-r--r--src/gui/gui.zig85
1 files changed, 58 insertions, 27 deletions
diff --git a/src/gui/gui.zig b/src/gui/gui.zig
index 4ce554f3..590d749d 100644
--- a/src/gui/gui.zig
+++ b/src/gui/gui.zig
@@ -3538,21 +3538,7 @@ fn dispatch(g: *Gui, in: *Input, sev: *const c.SDL_Event) void {
};
g.pointer_mapped = true;
g.pointer_cell = mc;
- const mods = pointerMods();
- in.post(.{
- .mouse = .{
- .button = button,
- .kind = if (b.down) .press else .release,
- .col = mc.col,
- .row = mc.row,
- .tag_hit = mc.tag_hit,
- .body_hit = mc.body_hit,
- .rule_above = mc.rule_above,
- .ctrl = mods.ctrl,
- .shift = mods.shift,
- .alt = mods.alt,
- },
- });
+ in.post(.{ .mouse = pointerMouse(button, if (b.down) .press else .release, mc, pointerMods()) });
},
c.SDL_EVENT_MOUSE_MOTION => {
const m = sev.motion;
@@ -3574,18 +3560,7 @@ fn dispatch(g: *Gui, in: *Input, sev: *const c.SDL_Event) void {
};
g.pointer_mapped = true;
g.pointer_cell = mc;
- const mods = pointerMods();
- in.post(.{ .mouse = .{
- .button = held orelse .none,
- .kind = if (held != null) .drag else .motion,
- .col = mc.col,
- .row = mc.row,
- .tag_hit = mc.tag_hit,
- .body_hit = mc.body_hit,
- .ctrl = mods.ctrl,
- .shift = mods.shift,
- .alt = mods.alt,
- } });
+ in.post(.{ .mouse = pointerMouse(held orelse .none, if (held != null) .drag else .motion, mc, pointerMods()) });
},
c.SDL_EVENT_MOUSE_WHEEL => {
const w = sev.wheel;
@@ -3980,6 +3955,22 @@ const WheelTurn = struct { x: f32 = 0, y: f32 = 0, integer_y: i32 = 0, mods: Poi
/// The modifiers held with a pointer event, as the core's Mouse carries them.
const PointerMods = struct { ctrl: bool = false, shift: bool = false, alt: bool = false };
+/// The core's Mouse for an SDL press, release or move over cell `mc`.
+fn pointerMouse(button: pardes.Mouse.Button, kind: pardes.Mouse.Kind, mc: MouseCell, mods: PointerMods) pardes.Mouse {
+ return .{
+ .button = button,
+ .kind = kind,
+ .col = mc.col,
+ .row = mc.row,
+ .tag_hit = mc.tag_hit,
+ .body_hit = mc.body_hit,
+ .rule_above = (kind == .press or kind == .release) and mc.rule_above,
+ .ctrl = mods.ctrl,
+ .shift = mods.shift,
+ .alt = mods.alt,
+ };
+}
+
fn pointerMods() PointerMods {
const m = c.SDL_GetModState();
return .{ .ctrl = (m & c.SDL_KMOD_CTRL) != 0, .shift = (m & c.SDL_KMOD_SHIFT) != 0, .alt = (m & c.SDL_KMOD_ALT) != 0 };
@@ -4948,6 +4939,46 @@ test "a wheel's notch is whole lines, a touchpad's fraction is not" {
try std.testing.expectEqual(@as(?i32, null), notchOf(std.math.nan(f32), 1));
}
+test "a click over codex in a terminal reaches its pty with its modifiers; with Shift it is pardes's" {
+ if (comptime !pardes.panes.terminal.enabled) return error.SkipZigTest;
+ const gpa = std.testing.allocator;
+ const core = try pardes.Pardes.init(gpa, .{ .cols = 60, .rows = 16, .tty_only = true });
+ defer core.deinit();
+ var frame: std.heap.ArenaAllocator = .init(gpa);
+ defer frame.deinit();
+ _ = try core.render(frame.allocator());
+ var in: Input = .{ .core = core };
+ var sent: std.ArrayList(u8) = .empty;
+ defer sent.deinit(gpa);
+ const take = struct {
+ fn f(core_: *pardes.Pardes, out: *std.ArrayList(u8)) ![]const u8 {
+ out.clearRetainingCapacity();
+ while (core_.nextEffect()) |effect| {
+ if (effect == .write and effect.write.pane == 0) try out.appendSlice(std.testing.allocator, effect.write.bytes.slice());
+ }
+ return out.items;
+ }
+ }.f;
+ _ = try take(core, &sent);
+ const pane = core.panes[0].?;
+ const r = core.rects[0];
+ const mc: MouseCell = .{ .col = r.x + config.GUTTER + 5, .row = core.bodyTop(pane, r) + 3 };
+ const next: MouseCell = .{ .col = mc.col + 1, .row = mc.row };
+ core.update(.{ .output = .{ .pane = 0, .bytes = "\x1b[?1049h\x1b[?1000h\x1b[?1002h\x1b[?1003h\x1b[?1006h" } });
+ _ = try take(core, &sent);
+ in.post(.{ .mouse = pointerMouse(.none, .motion, mc, .{}) });
+ try std.testing.expectEqualStrings("\x1b[<35;6;4M", try take(core, &sent));
+ in.post(.{ .mouse = pointerMouse(.left, .press, mc, .{ .ctrl = true }) });
+ try std.testing.expectEqualStrings("\x1b[<16;6;4M", try take(core, &sent));
+ in.post(.{ .mouse = pointerMouse(.left, .drag, next, .{}) });
+ try std.testing.expectEqualStrings("\x1b[<32;7;4M", try take(core, &sent));
+ in.post(.{ .mouse = pointerMouse(.left, .release, next, .{}) });
+ try std.testing.expectEqualStrings("\x1b[<0;7;4m", try take(core, &sent));
+ in.post(.{ .mouse = pointerMouse(.middle, .press, mc, .{ .shift = true }) });
+ in.post(.{ .mouse = pointerMouse(.middle, .release, mc, .{ .shift = true }) });
+ try std.testing.expectEqualStrings("", try take(core, &sent));
+}
+
test "a wheel over codex in a terminal reaches its pty as the mouse reports it asked for" {
if (comptime !pardes.panes.terminal.enabled) return error.SkipZigTest;
const gpa = std.testing.allocator;