Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions graphcode-windows/src/App.zig
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const InputRouter = @import("InputRouter.zig");
const MainWindow = @import("MainWindow.zig");
const TerminalWorkspace = @import("TerminalWorkspace.zig");
const Tokens = @import("DesignTokens.zig");
const Dpi = @import("Dpi.zig");
const Wire = @import("Wire.zig");
const WorktreeStatus = @import("WorktreeStatus.zig");
const TrayModule = @import("Tray.zig");
Expand Down Expand Up @@ -191,6 +192,7 @@ pub const App = struct {
workspace: ?*TerminalWorkspace.Workspace = null,
navigation_cursor: Navigation.Cursor = .{},
workspace_controls: WorkspaceControls.State = .{ .panel_visible = false },
dpi: u32 = Dpi.base_dpi,
surface: GraphCanvas.Surface = .project,
canvas_layout_store: ?CanvasLayoutStore.Store = null,
quick_chats_requested: bool = false,
Expand Down Expand Up @@ -4034,6 +4036,29 @@ fn onWindowMessage(
result.* = 0;
return true;
},
c.WM_DPICHANGED => {
const dpi = @as(u32, @intCast(wparam & 0xffff));
app.dpi = Dpi.normalize(dpi);
if (lparam != 0) {
const suggested: *const c.RECT = @ptrFromInt(@as(usize, @bitCast(lparam)));
_ = c.SetWindowPos(
hwnd,
null,
suggested.left,
suggested.top,
suggested.right - suggested.left,
suggested.bottom - suggested.top,
c.SWP_NOZORDER | c.SWP_NOACTIVATE,
);
}
app.layoutWorkspace();
app.clampSidebarScroll();
app.layoutEmptyStateControls();
app.syncAccessibility();
_ = c.InvalidateRect(hwnd, null, 0);
result.* = 0;
return true;
},
c.WM_TIMER => if (wparam == MainWindow.timer_id) {
app.smoke_tick += 1;
if (!app.tray.added and app.smoke_tick % 10 == 0) {
Expand Down
37 changes: 37 additions & 0 deletions graphcode-windows/src/Dpi.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
const std = @import("std");

pub const base_dpi: u32 = 96;

pub fn normalize(dpi: u32) u32 {
return if (dpi == 0) base_dpi else dpi;
}

pub fn scale(value: i32, dpi: u32) i32 {
const normalized = normalize(dpi);
const scaled = @divTrunc(
@as(i64, value) * @as(i64, normalized) + @as(i64, base_dpi / 2),
@as(i64, base_dpi),
);
return @intCast(scaled);
}

pub fn unscale(value: i32, dpi: u32) i32 {
const normalized = normalize(dpi);
const scaled = @divTrunc(
@as(i64, value) * @as(i64, base_dpi) + @as(i64, normalized / 2),
@as(i64, normalized),
);
return @intCast(scaled);
}

test "DPI scaling rounds at the native boundary" {
try std.testing.expectEqual(@as(i32, 100), scale(100, 96));
try std.testing.expectEqual(@as(i32, 125), scale(100, 120));
try std.testing.expectEqual(@as(i32, 150), scale(100, 144));
try std.testing.expectEqual(@as(i32, 100), unscale(125, 120));
}

test "zero DPI falls back to the Windows base DPI" {
try std.testing.expectEqual(base_dpi, normalize(0));
try std.testing.expectEqual(@as(i32, 42), scale(42, 0));
}
16 changes: 8 additions & 8 deletions graphcode-windows/src/GraphContextMenu.zig
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ pub fn show(
.quick_chats => append(menu, ids.new_quick_chat, "New Chat"),
.project => |project| {
append(menu, ids.open_project, "Open Project");
append(menu, ids.new_project_loop, "New Loop...");
append(menu, ids.new_project_loop, "New Loop...\tCtrl+N");
separator(menu);
append(menu, ids.inspect_project_worktrees, "Worktrees...");
append(menu, ids.project_settings, "Project Settings...");
Expand All @@ -146,7 +146,7 @@ pub fn show(
append(menu, ids.delete_project_loops, "Delete All Loops...");
},
.node => |node| {
append(menu, ids.open_terminal, "Open Terminal");
append(menu, ids.open_terminal, "Open Terminal\tEnter");
if (node.unwired) {
append(menu, ids.wire_node, "Wire it up");
append(menu, ids.mark_entry, "Mark as entry");
Expand All @@ -158,19 +158,19 @@ pub fn show(
appendEnabled(menu, ids.arm_composite, "Arm Schedule", node.can_arm);
separator(menu);
}
append(menu, ids.edit_node, "Edit Details...");
append(menu, ids.rename_node, "Rename...");
append(menu, ids.stop_node, "Stop");
append(menu, ids.delete_node, "Delete Loop...");
append(menu, ids.edit_node, "Edit Details...\tCtrl+E");
append(menu, ids.rename_node, "Rename...\tF2");
append(menu, ids.stop_node, "Stop\tCtrl+S");
append(menu, ids.delete_node, "Delete Loop...\tDelete");
},
.edge => {
append(menu, ids.edit_edge, "Edit Edge...");
append(menu, ids.delete_edge, "Delete Edge");
},
.quick_chat => {
append(menu, ids.open_quick_chat, "Open Chat");
append(menu, ids.rename_quick_chat, "Rename...");
append(menu, ids.delete_quick_chat, "Delete Chat...");
append(menu, ids.rename_quick_chat, "Rename...\tCtrl+Shift+Q");
append(menu, ids.delete_quick_chat, "Delete Chat...\tCtrl+Shift+Delete");
},
}
const command = c.TrackPopupMenu(
Expand Down
Loading