From 82405e8c177de446d03c340b4b6876370d79883a Mon Sep 17 00:00:00 2001 From: David Robillard Date: Fri, 20 May 2022 19:44:23 -0400 Subject: Add puglSetPosition() and puglSetSize() These are redundant with puglSetFrame in a sense, but allow setting the size of a view without the position, or vice-versa. This API also maps more nicely to Wayland, where applications can not position themselves (but can resize). --- examples/pugl_embed_demo.c | 22 +++++------- examples/pugl_window_demo.c | 35 ++++++++----------- include/pugl/pugl.h | 28 +++++++++++++--- src/mac.m | 82 +++++++++++++++++++++++++++++++++++++++------ src/win.c | 82 ++++++++++++++++++++++++++++++++++++++++----- src/x11.c | 53 ++++++++++++++++++++++++++--- 6 files changed, 239 insertions(+), 63 deletions(-) diff --git a/examples/pugl_embed_demo.c b/examples/pugl_embed_demo.c index ae3956a..af48a15 100644 --- a/examples/pugl_embed_demo.c +++ b/examples/pugl_embed_demo.c @@ -119,30 +119,24 @@ onKeyPress(PuglView* view, const PuglKeyEvent* event, const char* prefix) fprintf(stderr, "%sPaste \"%s\"\n", prefix, text); } else if (event->state & PUGL_MOD_SHIFT) { if (event->key == PUGL_KEY_UP) { - frame.height = (PuglSpan)(frame.height + 10u); + puglSetSize(view, frame.width, frame.height - 10u); } else if (event->key == PUGL_KEY_DOWN) { - frame.height = (PuglSpan)(frame.height - 10u); + puglSetSize(view, frame.width, frame.height + 10u); } else if (event->key == PUGL_KEY_LEFT) { - frame.width = (PuglSpan)(frame.width - 10u); + puglSetSize(view, frame.width - 10u, frame.height); } else if (event->key == PUGL_KEY_RIGHT) { - frame.width = (PuglSpan)(frame.width + 10u); - } else { - return; + puglSetSize(view, frame.width + 10u, frame.height); } - puglSetFrame(view, frame); } else { if (event->key == PUGL_KEY_UP) { - frame.y = (PuglCoord)(frame.y - 10); + puglSetPosition(view, frame.x, frame.y - 10); } else if (event->key == PUGL_KEY_DOWN) { - frame.y = (PuglCoord)(frame.y + 10); + puglSetPosition(view, frame.x, frame.y + 10); } else if (event->key == PUGL_KEY_LEFT) { - frame.x = (PuglCoord)(frame.x - 10); + puglSetPosition(view, frame.x - 10, frame.y); } else if (event->key == PUGL_KEY_RIGHT) { - frame.x = (PuglCoord)(frame.x + 10); - } else { - return; + puglSetPosition(view, frame.x + 10, frame.y); } - puglSetFrame(view, frame); } } diff --git a/examples/pugl_window_demo.c b/examples/pugl_window_demo.c index 8d79f00..3b8da31 100644 --- a/examples/pugl_window_demo.c +++ b/examples/pugl_window_demo.c @@ -70,30 +70,24 @@ onKeyPress(PuglView* view, const PuglKeyEvent* event) app->quit = 1; } else if (event->state & PUGL_MOD_SHIFT) { if (event->key == PUGL_KEY_UP) { - frame.height = (PuglSpan)(frame.height + 10u); + puglSetSize(view, frame.width, frame.height - 10u); } else if (event->key == PUGL_KEY_DOWN) { - frame.height = (PuglSpan)(frame.height - 10u); + puglSetSize(view, frame.width, frame.height + 10u); } else if (event->key == PUGL_KEY_LEFT) { - frame.width = (PuglSpan)(frame.width - 10u); + puglSetSize(view, frame.width - 10u, frame.height); } else if (event->key == PUGL_KEY_RIGHT) { - frame.width = (PuglSpan)(frame.width + 10u); - } else { - return; + puglSetSize(view, frame.width + 10u, frame.height); } - puglSetFrame(view, frame); } else { if (event->key == PUGL_KEY_UP) { - frame.y = (PuglCoord)(frame.y - 10); + puglSetPosition(view, frame.x, frame.y - 10); } else if (event->key == PUGL_KEY_DOWN) { - frame.y = (PuglCoord)(frame.y + 10); + puglSetPosition(view, frame.x, frame.y + 10); } else if (event->key == PUGL_KEY_LEFT) { - frame.x = (PuglCoord)(frame.x - 10); + puglSetPosition(view, frame.x - 10, frame.y); } else if (event->key == PUGL_KEY_RIGHT) { - frame.x = (PuglCoord)(frame.x + 10); - } else { - return; + puglSetPosition(view, frame.x + 10, frame.y); } - puglSetFrame(view, frame); } } @@ -186,17 +180,16 @@ main(int argc, char** argv) PuglStatus st = PUGL_SUCCESS; for (unsigned i = 0; i < 2; ++i) { - CubeView* cube = &app.cubes[i]; - PuglView* view = cube->view; - const PuglRect frame = {(PuglCoord)(pad + (128.0 + pad) * i), - (PuglCoord)(pad + (128.0 + pad) * i), - 512u, - 512u}; + CubeView* cube = &app.cubes[i]; + PuglView* view = cube->view; cube->dist = 10; puglSetWindowTitle(view, "Pugl Window Demo"); - puglSetFrame(view, frame); + puglSetPosition(view, + (PuglCoord)(pad + (128u + pad) * i), + (PuglCoord)(pad + (128u + pad) * i)); + puglSetSizeHint(view, PUGL_DEFAULT_SIZE, 512, 512); puglSetSizeHint(view, PUGL_MIN_SIZE, 128, 128); puglSetSizeHint(view, PUGL_MAX_SIZE, 2048, 2048); diff --git a/include/pugl/pugl.h b/include/pugl/pugl.h index 3fc124e..a7dd7eb 100644 --- a/include/pugl/pugl.h +++ b/include/pugl/pugl.h @@ -1000,14 +1000,34 @@ PUGL_API PuglStatus puglSetFrame(PuglView* view, PuglRect frame); +/** + Set the current position of the view. + + @return #PUGL_UNKNOWN_ERROR on failure, in which case the view frame is + unchanged. +*/ +PUGL_API +PuglStatus +puglSetPosition(PuglView* view, int x, int y); + +/** + Set the current size of the view. + + @return #PUGL_UNKNOWN_ERROR on failure, in which case the view frame is + unchanged. +*/ +PUGL_API +PuglStatus +puglSetSize(PuglView* view, unsigned width, unsigned height); + /** Set a size hint for the view. - This can be used to set the default, minimum, and maximum size of a view, as - well as the supported range of aspect ratios. + This can be used to set the default, minimum, and maximum size of a view, + as well as the supported range of aspect ratios. - This should be called before puglResize() so the initial window for the view - can be configured correctly. + This should be called before puglResize() so the initial window for the + view can be configured correctly. @return #PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is not yet realized. diff --git a/src/mac.m b/src/mac.m index 7608ec8..67422a5 100644 --- a/src/mac.m +++ b/src/mac.m @@ -1368,28 +1368,88 @@ puglSetWindowTitle(PuglView* view, const char* title) PuglStatus puglSetFrame(PuglView* view, const PuglRect frame) { - PuglInternals* const impl = view->impl; + PuglInternals* const impl = view->impl; + const NSRect framePx = rectToNsRect(frame); + const NSRect framePt = nsRectToPoints(view, framePx); - // Update view frame to exactly the requested frame in Pugl coordinates + // Update view frame to exactly the requested frame view->frame = frame; - const NSRect framePx = rectToNsRect(frame); - const NSRect framePt = nsRectToPoints(view, framePx); if (impl->window) { - // Resize window to fit new content rect const NSRect screenPt = rectToScreen(viewScreen(view), framePt); - const NSRect winFrame = [impl->window frameRectForContentRect:screenPt]; + // Move and resize window to fit new content rect + const NSRect winFrame = [impl->window frameRectForContentRect:screenPt]; [impl->window setFrame:winFrame display:NO]; + + // Resize views + const NSRect sizePx = NSMakeRect(0, 0, frame.width, frame.height); + const NSRect sizePt = [impl->drawView convertRectFromBacking:sizePx]; + [impl->wrapperView setFrame:sizePt]; + [impl->drawView setFrame:sizePt]; + } else { + // Resize view + const NSRect sizePx = NSMakeRect(0, 0, frame.width, frame.height); + const NSRect sizePt = [impl->drawView convertRectFromBacking:sizePx]; + + [impl->wrapperView setFrame:framePt]; + [impl->drawView setFrame:sizePt]; + } + + return PUGL_SUCCESS; +} + +PuglStatus +puglSetPosition(PuglView* const view, const int x, const int y) +{ + if (x > INT16_MAX || y > INT16_MAX) { + return PUGL_BAD_PARAMETER; + } + + const PuglRect frame = { + (PuglCoord)x, (PuglCoord)y, view->frame.height, view->frame.height}; + + PuglInternals* const impl = view->impl; + if (impl->window) { + return puglSetFrame(view, frame); } - // Resize views - const NSRect sizePx = NSMakeRect(0, 0, frame.width, frame.height); - const NSRect sizePt = [impl->drawView convertRectFromBacking:sizePx]; + const NSRect framePx = rectToNsRect(frame); + const NSRect framePt = nsRectToPoints(view, framePx); + [impl->wrapperView setFrameOrigin:framePt.origin]; + + const NSRect drawPx = NSMakeRect(0, 0, frame.width, frame.height); + const NSRect drawPt = [impl->drawView convertRectFromBacking:drawPx]; + [impl->drawView setFrameOrigin:drawPt.origin]; - [impl->wrapperView setFrame:(impl->window ? sizePt : framePt)]; - [impl->drawView setFrame:sizePt]; + view->frame = frame; + return PUGL_SUCCESS; +} + +PuglStatus +puglSetSize(PuglView* const view, const unsigned width, const unsigned height) +{ + if (width > INT16_MAX || height > INT16_MAX) { + return PUGL_BAD_PARAMETER; + } + const PuglRect frame = { + view->frame.x, view->frame.y, (PuglSpan)width, (PuglSpan)height}; + + PuglInternals* const impl = view->impl; + if (impl->window) { + return puglSetFrame(view, frame); + } + + const NSRect framePx = rectToNsRect(frame); + const NSRect framePt = nsRectToPoints(view, framePx); + [impl->wrapperView setFrameSize:framePt.size]; + + const NSRect drawPx = NSMakeRect(0, 0, frame.width, frame.height); + const NSRect drawPt = [impl->drawView convertRectFromBacking:drawPx]; + [impl->drawView setFrameSize:drawPt.size]; + + view->frame = frame; return PUGL_SUCCESS; } diff --git a/src/win.c b/src/win.c index 34f46d9..26dd4c8 100644 --- a/src/win.c +++ b/src/win.c @@ -984,17 +984,27 @@ puglSetWindowTitle(PuglView* view, const char* title) return PUGL_SUCCESS; } +static RECT +adjustedWindowRect(PuglView* const view, + const long x, + const long y, + const long width, + const long height) +{ + const unsigned flags = puglWinGetWindowFlags(view); + const unsigned exFlags = puglWinGetWindowExFlags(view); + + RECT rect = {(long)x, (long)y, (long)x + (long)width, (long)y + (long)height}; + AdjustWindowRectEx(&rect, flags, FALSE, exFlags); + return rect; +} + PuglStatus puglSetFrame(PuglView* view, const PuglRect frame) { if (view->impl->hwnd) { - RECT rect = {(long)frame.x, - (long)frame.y, - (long)frame.x + (long)frame.width, - (long)frame.y + (long)frame.height}; - - AdjustWindowRectEx( - &rect, puglWinGetWindowFlags(view), FALSE, puglWinGetWindowExFlags(view)); + const RECT rect = + adjustedWindowRect(view, frame.x, frame.y, frame.width, frame.height); if (!SetWindowPos(view->impl->hwnd, HWND_TOP, @@ -1011,13 +1021,69 @@ puglSetFrame(PuglView* view, const PuglRect frame) return PUGL_SUCCESS; } +PuglStatus +puglSetPosition(PuglView* const view, const int x, const int y) +{ + if (x > INT16_MAX || y > INT16_MAX) { + return PUGL_BAD_PARAMETER; + } + + if (view->impl->hwnd) { + const RECT rect = + adjustedWindowRect(view, x, y, view->frame.width, view->frame.height); + + if (!SetWindowPos(view->impl->hwnd, + HWND_TOP, + rect.left, + rect.top, + 0, + 0, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | + SWP_NOSIZE)) { + return PUGL_UNKNOWN_ERROR; + } + } + + view->frame.x = (PuglCoord)x; + view->frame.y = (PuglCoord)y; + return PUGL_SUCCESS; +} + +PuglStatus +puglSetSize(PuglView* const view, const unsigned width, const unsigned height) +{ + if (width > INT16_MAX || height > INT16_MAX) { + return PUGL_BAD_PARAMETER; + } + + if (view->impl->hwnd) { + const RECT rect = adjustedWindowRect( + view, view->frame.x, view->frame.y, (long)width, (long)height); + + if (!SetWindowPos(view->impl->hwnd, + HWND_TOP, + 0, + 0, + rect.right - rect.left, + rect.bottom - rect.top, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | + SWP_NOMOVE)) { + return PUGL_UNKNOWN_ERROR; + } + } + + view->frame.width = (PuglSpan)width; + view->frame.height = (PuglSpan)height; + return PUGL_SUCCESS; +} + PuglStatus puglSetSizeHint(PuglView* const view, const PuglSizeHint hint, const PuglSpan width, const PuglSpan height) { - if ((unsigned)hint > (unsigned)PUGL_MAX_ASPECT || width < 0 || height < 0) { + if ((unsigned)hint > (unsigned)PUGL_MAX_ASPECT) { return PUGL_BAD_PARAMETER; } diff --git a/src/x11.c b/src/x11.c index f5a5461..5ae6b12 100644 --- a/src/x11.c +++ b/src/x11.c @@ -1026,11 +1026,15 @@ mergeExposeEvents(PuglExposeEvent* const dst, const PuglExposeEvent* const src) if (!dst->type) { *dst = *src; } else { - const double max_x = MAX(dst->x + dst->width, src->x + src->width); - const double max_y = MAX(dst->y + dst->height, src->y + src->height); - - dst->x = MIN(dst->x, src->x); - dst->y = MIN(dst->y, src->y); + const int dst_r = dst->x + dst->width; + const int src_r = src->x + src->width; + const int max_x = MAX(dst_r, src_r); + const int dst_b = dst->y + dst->height; + const int src_b = src->y + src->height; + const int max_y = MAX(dst_b, src_b); + + dst->x = (PuglCoord)MIN(dst->x, src->x); + dst->y = (PuglCoord)MIN(dst->y, src->y); dst->width = (PuglSpan)(max_x - dst->x); dst->height = (PuglSpan)(max_y - dst->y); } @@ -1381,6 +1385,45 @@ puglSetFrame(PuglView* const view, const PuglRect frame) return PUGL_SUCCESS; } +PuglStatus +puglSetPosition(PuglView* const view, const int x, const int y) +{ + Display* const display = view->world->impl->display; + const Window win = view->impl->win; + + if (x > INT16_MAX || y > INT16_MAX) { + return PUGL_BAD_PARAMETER; + } + + if (win && !XMoveWindow(display, win, x, y)) { + return PUGL_UNKNOWN_ERROR; + } + + view->frame.x = (PuglCoord)x; + view->frame.y = (PuglCoord)y; + return PUGL_SUCCESS; +} + +PuglStatus +puglSetSize(PuglView* const view, const unsigned width, const unsigned height) +{ + Display* const display = view->world->impl->display; + const Window win = view->impl->win; + + if (width > INT16_MAX || height > INT16_MAX) { + return PUGL_BAD_PARAMETER; + } + + if (win) { + return XResizeWindow(display, win, width, height) ? PUGL_SUCCESS + : PUGL_UNKNOWN_ERROR; + } + + view->frame.width = (PuglSpan)width; + view->frame.height = (PuglSpan)height; + return PUGL_SUCCESS; +} + PuglStatus puglSetSizeHint(PuglView* const view, const PuglSizeHint hint, -- cgit v1.2.1