From eada1042452e8708ca6c65f7c23ac3c59e4c53f0 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Fri, 26 Jul 2019 00:57:49 +0200 Subject: Windows: Implement size constraints There are two possible approaches to take here: try to expand dimensions that are not being explicitly resized (for example expand the bottom when dragging right), or just stop single-dimension resizes if they would go out of range. I chose the latter here for two reasons: it's hard to always do something smooth and unsurprising with the first approach (and it would require more code), and it can be nice from the user's perspective to easily be able to resize the window to exactly one of its aspect ratio limits. For example, it is very easy to drag pugl_test to 1:1 or 16:9. In other words, simplicity and user power wins. --- pugl/pugl.h | 4 ++++ pugl/pugl_win.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ test/pugl_test.c | 2 +- 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/pugl/pugl.h b/pugl/pugl.h index 59d26fe..3e0578e 100644 --- a/pugl/pugl.h +++ b/pugl/pugl.h @@ -457,6 +457,10 @@ puglInitWindowMinSize(PuglView* view, int width, int height); The x and y values here represent a ratio of width to height. To set a fixed aspect ratio, set the minimum and maximum values to the same ratio. + + Note that setting different minimum and maximum constraints does not + currenty work on MacOS (the minimum is used), so only setting a fixed aspect + ratio works properly across all platforms. */ PUGL_API void puglInitWindowAspectRatio(PuglView* view, diff --git a/pugl/pugl_win.c b/pugl/pugl_win.c index 1c93ea6..b691295 100644 --- a/pugl/pugl_win.c +++ b/pugl/pugl_win.c @@ -634,6 +634,45 @@ stopFlashing(PuglView* view) } } +static void +constrainAspect(const PuglView* const view, + RECT* const size, + const WPARAM wParam) +{ + const float minAspect = view->min_aspect_x / (float)view->min_aspect_y; + const float maxAspect = view->max_aspect_x / (float)view->max_aspect_y; + const int w = size->right - size->left; + const int h = size->bottom - size->top; + const float a = w / (float)h; + + switch (wParam) { + case WMSZ_TOP: + size->top = (a < minAspect ? (LONG)(size->bottom - w * minAspect) : + a > maxAspect ? (LONG)(size->bottom - w * maxAspect) : + size->top); + break; + case WMSZ_TOPRIGHT: + case WMSZ_RIGHT: + case WMSZ_BOTTOMRIGHT: + size->right = (a < minAspect ? (LONG)(size->left + h * minAspect) : + a > maxAspect ? (LONG)(size->left + h * maxAspect) : + size->right); + break; + case WMSZ_BOTTOM: + size->bottom = (a < minAspect ? (LONG)(size->top + w * minAspect) : + a > maxAspect ? (LONG)(size->top + w * maxAspect) : + size->bottom); + break; + case WMSZ_BOTTOMLEFT: + case WMSZ_LEFT: + case WMSZ_TOPLEFT: + size->left = (a < minAspect ? (LONG)(size->right - h * minAspect) : + a > maxAspect ? (LONG)(size->right - h * maxAspect) : + size->left); + break; + } +} + static LRESULT handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) { @@ -661,6 +700,12 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) RDW_INVALIDATE|RDW_ALLCHILDREN|RDW_INTERNALPAINT| RDW_UPDATENOW); break; + case WM_SIZING: + if (view->min_aspect_x) { + constrainAspect(view, (RECT*)lParam, wParam); + return TRUE; + } + break; case WM_ENTERSIZEMOVE: view->impl->resizing = true; SetTimer(view->impl->hwnd, diff --git a/test/pugl_test.c b/test/pugl_test.c index a609027..f011962 100644 --- a/test/pugl_test.c +++ b/test/pugl_test.c @@ -170,7 +170,7 @@ main(int argc, char** argv) puglInitWindowClass(view, "PuglTest"); puglInitWindowSize(view, 512, 512); puglInitWindowMinSize(view, 256, 256); - puglInitWindowAspectRatio(view, 1, 1, 1, 1); + puglInitWindowAspectRatio(view, 1, 1, 16, 9); puglInitResizable(view, resizable); puglInitWindowHint(view, PUGL_SAMPLES, samples); -- cgit v1.2.1