win32 gui: track and use window bounds to prevent infinite shrinkage
This commit is contained in:
parent
7d138a742c
commit
e542ccb8f1
2 changed files with 59 additions and 34 deletions
|
@ -1,4 +1,10 @@
|
||||||
{
|
{
|
||||||
|
"project": {
|
||||||
|
"press": [
|
||||||
|
["ctrl+=", "adjust_fontsize", 1.0],
|
||||||
|
["ctrl+-", "adjust_fontsize", -1.0]
|
||||||
|
]
|
||||||
|
},
|
||||||
"normal": {
|
"normal": {
|
||||||
"press": [
|
"press": [
|
||||||
["ctrl+g", "cancel"],
|
["ctrl+g", "cancel"],
|
||||||
|
|
|
@ -282,6 +282,7 @@ const State = struct {
|
||||||
currently_rendered_cell_size: ?XY(i32) = null,
|
currently_rendered_cell_size: ?XY(i32) = null,
|
||||||
background: ?u32 = null,
|
background: ?u32 = null,
|
||||||
last_sizing_edge: ?win32.WPARAM = null,
|
last_sizing_edge: ?win32.WPARAM = null,
|
||||||
|
bounds: ?WindowBounds = null,
|
||||||
};
|
};
|
||||||
fn stateFromHwnd(hwnd: win32.HWND) *State {
|
fn stateFromHwnd(hwnd: win32.HWND) *State {
|
||||||
std.debug.assert(hwnd == global.state.?.hwnd);
|
std.debug.assert(hwnd == global.state.?.hwnd);
|
||||||
|
@ -403,19 +404,19 @@ fn calcWindowPlacement(
|
||||||
.x = win32.scaleDpi(i32, @intCast(initial_window_x), result.dpi.x),
|
.x = win32.scaleDpi(i32, @intCast(initial_window_x), result.dpi.x),
|
||||||
.y = win32.scaleDpi(i32, @intCast(initial_window_y), result.dpi.y),
|
.y = win32.scaleDpi(i32, @intCast(initial_window_y), result.dpi.y),
|
||||||
};
|
};
|
||||||
const unadjusted_size: XY(i32) = .{
|
const bounding_size: XY(i32) = .{
|
||||||
.x = @min(wanted_size.x, work_size.x),
|
.x = @min(wanted_size.x, work_size.x),
|
||||||
.y = @min(wanted_size.y, work_size.y),
|
.y = @min(wanted_size.y, work_size.y),
|
||||||
};
|
};
|
||||||
const unadjusted_rect: win32.RECT = ddui.rectIntFromSize(.{
|
const bouding_rect: win32.RECT = ddui.rectIntFromSize(.{
|
||||||
.left = work_rect.left + @divTrunc(work_size.x - unadjusted_size.x, 2),
|
.left = work_rect.left + @divTrunc(work_size.x - bounding_size.x, 2),
|
||||||
.top = work_rect.top + @divTrunc(work_size.y - unadjusted_size.y, 2),
|
.top = work_rect.top + @divTrunc(work_size.y - bounding_size.y, 2),
|
||||||
.width = unadjusted_size.x,
|
.width = bounding_size.x,
|
||||||
.height = unadjusted_size.y,
|
.height = bounding_size.y,
|
||||||
});
|
});
|
||||||
const adjusted_rect: win32.RECT = shrinkWindowRectForCells(
|
const adjusted_rect: win32.RECT = calcWindowRect(
|
||||||
dpi,
|
dpi,
|
||||||
unadjusted_rect,
|
bouding_rect,
|
||||||
null,
|
null,
|
||||||
cell_size,
|
cell_size,
|
||||||
);
|
);
|
||||||
|
@ -637,7 +638,16 @@ pub fn updateScreen(screen: *const vaxis.Screen) void {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn updateWindowSize(hwnd: win32.HWND, edge: ?win32.WPARAM) void {
|
const WindowBounds = struct {
|
||||||
|
token: win32.RECT,
|
||||||
|
rect: win32.RECT,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn updateWindowSize(
|
||||||
|
hwnd: win32.HWND,
|
||||||
|
edge: ?win32.WPARAM,
|
||||||
|
bounds_ref: *?WindowBounds,
|
||||||
|
) void {
|
||||||
const dpi = win32.dpiFromHwnd(hwnd);
|
const dpi = win32.dpiFromHwnd(hwnd);
|
||||||
const text_format_editor = global.text_format_editor.getOrCreate(FontCacheParams{ .dpi = dpi, .fontsize = getFontSize() });
|
const text_format_editor = global.text_format_editor.getOrCreate(FontCacheParams{ .dpi = dpi, .fontsize = getFontSize() });
|
||||||
const cell_size = getCellSize(text_format_editor);
|
const cell_size = getCellSize(text_format_editor);
|
||||||
|
@ -647,12 +657,26 @@ fn updateWindowSize(hwnd: win32.HWND, edge: ?win32.WPARAM) void {
|
||||||
"GetWindowRect",
|
"GetWindowRect",
|
||||||
win32.GetLastError(),
|
win32.GetLastError(),
|
||||||
);
|
);
|
||||||
const new_rect = shrinkWindowRectForCells(
|
|
||||||
|
const restored_bounds: ?win32.RECT = blk: {
|
||||||
|
if (bounds_ref.*) |b| {
|
||||||
|
if (std.meta.eql(b.token, window_rect)) {
|
||||||
|
break :blk b.rect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break :blk null;
|
||||||
|
};
|
||||||
|
const bounds = if (restored_bounds) |b| b else window_rect;
|
||||||
|
const new_rect = calcWindowRect(
|
||||||
dpi,
|
dpi,
|
||||||
window_rect,
|
bounds,
|
||||||
edge,
|
edge,
|
||||||
cell_size,
|
cell_size,
|
||||||
);
|
);
|
||||||
|
bounds_ref.* = .{
|
||||||
|
.token = new_rect,
|
||||||
|
.rect = if (restored_bounds) |b| b else new_rect,
|
||||||
|
};
|
||||||
setWindowPosRect(hwnd, new_rect);
|
setWindowPosRect(hwnd, new_rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -680,8 +704,8 @@ fn getCellSize(text_format: *win32.IDWriteTextFormat) XY(i32) {
|
||||||
if (hr < 0) fatalHr("GetMetrics", hr);
|
if (hr < 0) fatalHr("GetMetrics", hr);
|
||||||
}
|
}
|
||||||
return .{
|
return .{
|
||||||
.x = @as(i32, @intFromFloat(@floor(metrics.width))),
|
.x = @max(1, @as(i32, @intFromFloat(@floor(metrics.width)))),
|
||||||
.y = @as(i32, @intFromFloat(@floor(metrics.height))),
|
.y = @max(1, @as(i32, @intFromFloat(@floor(metrics.height)))),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1198,7 +1222,7 @@ fn WndProc(
|
||||||
const new_dpi: u32 = @intCast(0xffffffff & wparam);
|
const new_dpi: u32 = @intCast(0xffffffff & wparam);
|
||||||
const text_format_editor = global.text_format_editor.getOrCreate(FontCacheParams{ .dpi = new_dpi, .fontsize = getFontSize() });
|
const text_format_editor = global.text_format_editor.getOrCreate(FontCacheParams{ .dpi = new_dpi, .fontsize = getFontSize() });
|
||||||
const cell_size = getCellSize(text_format_editor);
|
const cell_size = getCellSize(text_format_editor);
|
||||||
const new_rect = shrinkWindowRectForCells(
|
const new_rect = calcWindowRect(
|
||||||
new_dpi,
|
new_dpi,
|
||||||
.{
|
.{
|
||||||
.left = 0,
|
.left = 0,
|
||||||
|
@ -1216,20 +1240,13 @@ fn WndProc(
|
||||||
return 1;
|
return 1;
|
||||||
},
|
},
|
||||||
win32.WM_DPICHANGED => {
|
win32.WM_DPICHANGED => {
|
||||||
|
const state = stateFromHwnd(hwnd);
|
||||||
const dpi = win32.dpiFromHwnd(hwnd);
|
const dpi = win32.dpiFromHwnd(hwnd);
|
||||||
if (dpi != win32.hiword(wparam)) @panic("unexpected hiword dpi");
|
if (dpi != win32.hiword(wparam)) @panic("unexpected hiword dpi");
|
||||||
if (dpi != win32.loword(wparam)) @panic("unexpected loword dpi");
|
if (dpi != win32.loword(wparam)) @panic("unexpected loword dpi");
|
||||||
const rect: *win32.RECT = @ptrFromInt(@as(usize, @bitCast(lparam)));
|
const rect: *win32.RECT = @ptrFromInt(@as(usize, @bitCast(lparam)));
|
||||||
if (0 == win32.SetWindowPos(
|
setWindowPosRect(hwnd, rect.*);
|
||||||
hwnd,
|
state.bounds = null;
|
||||||
null, // ignored via NOZORDER
|
|
||||||
rect.left,
|
|
||||||
rect.top,
|
|
||||||
rect.right - rect.left,
|
|
||||||
rect.bottom - rect.top,
|
|
||||||
.{ .NOZORDER = 1 },
|
|
||||||
)) fatalWin32("SetWindowPos", win32.GetLastError());
|
|
||||||
sendResize(hwnd);
|
|
||||||
return 0;
|
return 0;
|
||||||
},
|
},
|
||||||
win32.WM_SIZE,
|
win32.WM_SIZE,
|
||||||
|
@ -1254,7 +1271,8 @@ fn WndProc(
|
||||||
},
|
},
|
||||||
win32.WM_EXITSIZEMOVE => {
|
win32.WM_EXITSIZEMOVE => {
|
||||||
const state = stateFromHwnd(hwnd);
|
const state = stateFromHwnd(hwnd);
|
||||||
updateWindowSize(hwnd, state.last_sizing_edge);
|
state.bounds = null;
|
||||||
|
updateWindowSize(hwnd, state.last_sizing_edge, &state.bounds);
|
||||||
state.last_sizing_edge = null;
|
state.last_sizing_edge = null;
|
||||||
return 0;
|
return 0;
|
||||||
},
|
},
|
||||||
|
@ -1292,9 +1310,10 @@ fn WndProc(
|
||||||
return WM_APP_SET_BACKGROUND_RESULT;
|
return WM_APP_SET_BACKGROUND_RESULT;
|
||||||
},
|
},
|
||||||
WM_APP_ADJUST_FONTSIZE => {
|
WM_APP_ADJUST_FONTSIZE => {
|
||||||
|
const state = stateFromHwnd(hwnd);
|
||||||
const amount: f32 = @bitCast(@as(u32, @intCast(0xFFFFFFFFF & wparam)));
|
const amount: f32 = @bitCast(@as(u32, @intCast(0xFFFFFFFFF & wparam)));
|
||||||
global.fontsize = @max(getFontSize() + amount, 1.0);
|
global.fontsize = @max(getFontSize() + amount, 1.0);
|
||||||
updateWindowSize(hwnd, win32.WMSZ_BOTTOMRIGHT);
|
updateWindowSize(hwnd, win32.WMSZ_BOTTOMRIGHT, &state.bounds);
|
||||||
win32.invalidateHwnd(hwnd);
|
win32.invalidateHwnd(hwnd);
|
||||||
return WM_APP_ADJUST_FONTSIZE_RESULT;
|
return WM_APP_ADJUST_FONTSIZE_RESULT;
|
||||||
},
|
},
|
||||||
|
@ -1392,15 +1411,15 @@ fn getClientSize(hwnd: win32.HWND) XY(i32) {
|
||||||
return .{ .x = rect.right, .y = rect.bottom };
|
return .{ .x = rect.right, .y = rect.bottom };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shrinkWindowRectForCells(
|
fn calcWindowRect(
|
||||||
dpi: u32,
|
dpi: u32,
|
||||||
rect: win32.RECT,
|
bouding_rect: win32.RECT,
|
||||||
maybe_edge: ?win32.WPARAM,
|
maybe_edge: ?win32.WPARAM,
|
||||||
cell_size: XY(i32),
|
cell_size: XY(i32),
|
||||||
) win32.RECT {
|
) win32.RECT {
|
||||||
const window_size: XY(i32) = .{
|
const window_size: XY(i32) = .{
|
||||||
.x = rect.right - rect.left,
|
.x = bouding_rect.right - bouding_rect.left,
|
||||||
.y = rect.bottom - rect.top,
|
.y = bouding_rect.bottom - bouding_rect.top,
|
||||||
};
|
};
|
||||||
const client_inset = getClientInset(dpi);
|
const client_inset = getClientInset(dpi);
|
||||||
const client_size: XY(i32) = .{
|
const client_size: XY(i32) = .{
|
||||||
|
@ -1427,22 +1446,22 @@ fn shrinkWindowRectForCells(
|
||||||
} else .{ .x = .both, .y = .both };
|
} else .{ .x = .both, .y = .both };
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.left = rect.left - switch (adjustments.x) {
|
.left = bouding_rect.left - switch (adjustments.x) {
|
||||||
.low => diff.x,
|
.low => diff.x,
|
||||||
.high => 0,
|
.high => 0,
|
||||||
.both => @divTrunc(diff.x, 2),
|
.both => @divTrunc(diff.x, 2),
|
||||||
},
|
},
|
||||||
.top = rect.top - switch (adjustments.y) {
|
.top = bouding_rect.top - switch (adjustments.y) {
|
||||||
.low => diff.y,
|
.low => diff.y,
|
||||||
.high => 0,
|
.high => 0,
|
||||||
.both => @divTrunc(diff.y, 2),
|
.both => @divTrunc(diff.y, 2),
|
||||||
},
|
},
|
||||||
.right = rect.right + switch (adjustments.x) {
|
.right = bouding_rect.right + switch (adjustments.x) {
|
||||||
.low => 0,
|
.low => 0,
|
||||||
.high => diff.x,
|
.high => diff.x,
|
||||||
.both => @divTrunc(diff.x + 1, 2),
|
.both => @divTrunc(diff.x + 1, 2),
|
||||||
},
|
},
|
||||||
.bottom = rect.bottom + switch (adjustments.y) {
|
.bottom = bouding_rect.bottom + switch (adjustments.y) {
|
||||||
.low => 0,
|
.low => 0,
|
||||||
.high => diff.y,
|
.high => diff.y,
|
||||||
.both => @divTrunc(diff.y + 1, 2),
|
.both => @divTrunc(diff.y + 1, 2),
|
||||||
|
|
Loading…
Add table
Reference in a new issue