[0.0.0] Capture window: a zoom slider, and fitting to the window, its width or its height
This commit is contained in:
parent
4323831801
commit
94d56f25b1
@ -9,6 +9,8 @@ VIEWER_MAX_TEXTURES :: 1200; // previews on the GPU at once, about 200 KB
|
||||
VIEWER_PREFETCH_ROWS :: 8; // most rows decoded ahead of the view, above and below
|
||||
VIEWER_UPLOAD_BUDGET_MS :: 4.0; // time per frame spent uploading previews
|
||||
VIEWER_FULL_WINDOW :: "Capture";
|
||||
VIEWER_MIN_ZOOM :: 5.0; // percent, for the full-size window
|
||||
VIEWER_MAX_ZOOM :: 800.0;
|
||||
|
||||
GPU_TEXTURE_MAX_SIDE :: 16384; // what D3D11 guarantees; larger images are scaled down to fit
|
||||
|
||||
@ -36,6 +38,14 @@ Viewer_Capture :: struct {
|
||||
in_flight: bool; // under viewer.mutex: queued for a worker, or being decoded
|
||||
}
|
||||
|
||||
// How the full-size window sizes its image.
|
||||
Viewer_Fit :: enum u8 {
|
||||
OFF; // at the zoom the slider sets
|
||||
WINDOW; // the whole image in the window
|
||||
WIDTH; // the window's width, scrolling down
|
||||
HEIGHT; // the window's height, scrolling across
|
||||
}
|
||||
|
||||
// Pixels a worker decoded, waiting for the main thread to upload them.
|
||||
Decoded :: struct {
|
||||
index: s32;
|
||||
@ -76,7 +86,8 @@ viewer: struct {
|
||||
full_source_width, full_source_height: s32;
|
||||
full_loading: bool;
|
||||
full_failed: bool;
|
||||
full_actual_size: bool;
|
||||
full_fit := Viewer_Fit.WINDOW;
|
||||
full_zoom: float = 100; // percent of the size it was captured at; set by the fit, unless OFF
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- startup and shutdown
|
||||
@ -498,11 +509,24 @@ viewer_full_window :: () { using ImGui;
|
||||
TextColored(app_theme.palette.dim, "% x %", viewer.full_source_width, viewer.full_source_height);
|
||||
}
|
||||
if viewer.full_loading { SameLine(); TextColored(app_theme.palette.dim, "Loading..."); }
|
||||
SameLine();
|
||||
Checkbox("Actual size", *viewer.full_actual_size);
|
||||
SameLine();
|
||||
TextColored(app_theme.palette.dim, "Left / Right: previous / next");
|
||||
|
||||
// Zoom is a percentage of the size the capture was taken at. A fit sets it from the window, larger
|
||||
// or smaller, and the slider shows what it works out to; moving the slider turns the fit off,
|
||||
// and the zoom then stays for the next capture.
|
||||
fit := viewer.full_fit;
|
||||
Text("Fit:");
|
||||
SameLine(); if RadioButton("Window", fit == .WINDOW) fit = .WINDOW;
|
||||
SameLine(); if RadioButton("Width", fit == .WIDTH) fit = .WIDTH;
|
||||
SameLine(); if RadioButton("Height", fit == .HEIGHT) fit = .HEIGHT;
|
||||
SameLine(); if RadioButton("Off", fit == .OFF) fit = .OFF;
|
||||
viewer.full_fit = fit;
|
||||
SameLine();
|
||||
SetNextItemWidth(260);
|
||||
if SliderFloat("Zoom", *viewer.full_zoom, VIEWER_MIN_ZOOM, VIEWER_MAX_ZOOM, "%.0f%%", .Logarithmic) viewer.full_fit = .OFF;
|
||||
SameLine();
|
||||
if SmallButton("100%") { viewer.full_fit = .OFF; viewer.full_zoom = 100; }
|
||||
|
||||
// Left and Right step through the captures in grid order while this window has focus.
|
||||
if IsWindowFocused(.RootAndChildWindows) {
|
||||
if IsKeyPressed(.LeftArrow) && viewer.full_index > 0 viewer_request_full(viewer.full_index - 1);
|
||||
@ -512,16 +536,28 @@ viewer_full_window :: () { using ImGui;
|
||||
if viewer.full_failed {
|
||||
TextColored(app_theme.palette.warning, "This capture cannot be shown; see the Event Log.");
|
||||
} else if viewer.full_texture.handle {
|
||||
w, h := cast(float) viewer.full_texture.width, cast(float) viewer.full_texture.height;
|
||||
BeginChild("image", .{0, 0}, .None, .HorizontalScrollbar);
|
||||
if viewer.full_actual_size {
|
||||
// At the size it was captured; an image scaled down to fit a texture is drawn back up.
|
||||
Image(gpu_texture_ref(viewer.full_texture), .{cast(float) viewer.full_source_width, cast(float) viewer.full_source_height});
|
||||
} else {
|
||||
available := GetContentRegionAvail();
|
||||
scale := min(min(available.x / w, available.y / h), 1.0); // fitted, never enlarged
|
||||
Image(gpu_texture_ref(viewer.full_texture), .{w * scale, h * scale});
|
||||
// Each fit keeps the same scrollbars from frame to frame. Otherwise fitting the width of a tall
|
||||
// image would bring up a vertical scrollbar, narrowing the area, changing the fit, and so on.
|
||||
flags := WindowFlags.HorizontalScrollbar;
|
||||
if viewer.full_fit == {
|
||||
case .WINDOW; flags = .NoScrollbar;
|
||||
case .WIDTH; flags |= .AlwaysVerticalScrollbar;
|
||||
case .HEIGHT; flags |= .AlwaysHorizontalScrollbar;
|
||||
}
|
||||
BeginChild("image", .{0, 0}, .None, flags);
|
||||
area := GetContentRegionAvail();
|
||||
|
||||
// Sized from the captured size, so an image scaled down to fit a texture is drawn back up.
|
||||
source_w, source_h := cast(float) viewer.full_source_width, cast(float) viewer.full_source_height;
|
||||
if source_w > 0 && source_h > 0 && area.x > 0 && area.y > 0 {
|
||||
if viewer.full_fit == {
|
||||
case .WINDOW; viewer.full_zoom = 100 * min(area.x / source_w, area.y / source_h);
|
||||
case .WIDTH; viewer.full_zoom = 100 * area.x / source_w;
|
||||
case .HEIGHT; viewer.full_zoom = 100 * area.y / source_h;
|
||||
}
|
||||
}
|
||||
zoom := clamp(viewer.full_zoom, VIEWER_MIN_ZOOM, VIEWER_MAX_ZOOM) / 100;
|
||||
Image(gpu_texture_ref(viewer.full_texture), .{source_w * zoom, source_h * zoom});
|
||||
EndChild();
|
||||
// The previous image stays up while the next one loads, so stepping through does not flicker.
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user