diff options
author | David Robillard <d@drobilla.net> | 2022-05-20 14:23:41 -0400 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2022-05-21 16:49:47 -0400 |
commit | 1cd37cad0a06fbb15c44fd59dd6b2c12a0812a76 (patch) | |
tree | d7760c11195b003dc27a6f86f0c47df51c0a32da | |
parent | 0fc1422e858bf9849b84aee2abeca3b553214b73 (diff) | |
download | pugl-1cd37cad0a06fbb15c44fd59dd6b2c12a0812a76.tar.gz pugl-1cd37cad0a06fbb15c44fd59dd6b2c12a0812a76.tar.bz2 pugl-1cd37cad0a06fbb15c44fd59dd6b2c12a0812a76.zip |
Add a uniform API for setting size hints
This collapses many functions into one, which makes the API more easily
extensible and reduces code size.
33 files changed, 356 insertions, 313 deletions
diff --git a/bindings/cpp/include/pugl/pugl.hpp b/bindings/cpp/include/pugl/pugl.hpp index 5387c91..5b47fe6 100644 --- a/bindings/cpp/include/pugl/pugl.hpp +++ b/bindings/cpp/include/pugl/pugl.hpp @@ -327,6 +327,15 @@ public: using Backend = PuglBackend; ///< @copydoc PuglBackend using NativeView = PuglNativeView; ///< @copydoc PuglNativeView +/// @copydoc PuglSizeHint +enum class SizeHint { + defaultSize, ///< @copydoc PUGL_DEFAULT_SIZE + minSize, ///< @copydoc PUGL_MIN_SIZE + maxSize, ///< @copydoc PUGL_MAX_SIZE + minAspect, ///< @copydoc PUGL_MIN_ASPECT + maxAspect, ///< @copydoc PUGL_MAX_ASPECT +}; + /// @copydoc PuglViewHint enum class ViewHint { useCompatProfile, ///< @copydoc PUGL_USE_COMPAT_PROFILE @@ -458,29 +467,11 @@ public: return static_cast<Status>(puglSetFrame(cobj(), frame)); } - /// @copydoc puglSetDefaultSize - Status setDefaultSize(int width, int height) noexcept - { - return static_cast<Status>(puglSetDefaultSize(cobj(), width, height)); - } - - /// @copydoc puglSetMinSize - Status setMinSize(int width, int height) noexcept - { - return static_cast<Status>(puglSetMinSize(cobj(), width, height)); - } - - /// @copydoc puglSetMaxSize - Status setMaxSize(int width, int height) noexcept - { - return static_cast<Status>(puglSetMaxSize(cobj(), width, height)); - } - - /// @copydoc puglSetAspectRatio - Status setAspectRatio(int minX, int minY, int maxX, int maxY) noexcept + /// @copydoc puglSetSizeHint + Status setSizeHint(SizeHint hint, PuglSpan width, PuglSpan height) noexcept { return static_cast<Status>( - puglSetAspectRatio(cobj(), minX, minY, maxX, maxY)); + puglSetSizeHint(cobj(), static_cast<PuglSizeHint>(hint), width, height)); } /** diff --git a/doc/conf.py.in b/doc/conf.py.in index 3fa8ea2..b208553 100644 --- a/doc/conf.py.in +++ b/doc/conf.py.in @@ -25,6 +25,7 @@ _opaque = [ "VkResult", "VkSurfaceKHR", "size_t", + "uint16_t", "uint32_t", "uintptr_t", ] diff --git a/examples/pugl_cairo_demo.c b/examples/pugl_cairo_demo.c index 2cd4493..cf34158 100644 --- a/examples/pugl_cairo_demo.c +++ b/examples/pugl_cairo_demo.c @@ -216,9 +216,9 @@ main(int argc, char** argv) PuglView* view = puglNewView(app.world); puglSetWindowTitle(view, "Pugl Cairo Demo"); - puglSetDefaultSize(view, 512, 512); - puglSetMinSize(view, 256, 256); - puglSetMaxSize(view, 2048, 2048); + puglSetSizeHint(view, PUGL_DEFAULT_SIZE, 512, 512); + puglSetSizeHint(view, PUGL_MIN_SIZE, 256, 256); + puglSetSizeHint(view, PUGL_MAX_SIZE, 2048, 2048); puglSetViewHint(view, PUGL_RESIZABLE, app.opts.resizable); puglSetHandle(view, &app); puglSetBackend(view, puglCairoBackend()); diff --git a/examples/pugl_cpp_demo.cpp b/examples/pugl_cpp_demo.cpp index 7794529..015e7aa 100644 --- a/examples/pugl_cpp_demo.cpp +++ b/examples/pugl_cpp_demo.cpp @@ -115,10 +115,11 @@ main(int argc, char** argv) world.setClassName("PuglCppDemo"); view.setWindowTitle("Pugl C++ Demo"); - view.setDefaultSize(512, 512); - view.setMinSize(64, 64); - view.setMaxSize(256, 256); - view.setAspectRatio(1, 1, 16, 9); + view.setSizeHint(pugl::SizeHint::defaultSize, 512, 512); + view.setSizeHint(pugl::SizeHint::minSize, 64, 64); + view.setSizeHint(pugl::SizeHint::maxSize, 1024, 1024); + view.setSizeHint(pugl::SizeHint::minAspect, 1, 1); + view.setSizeHint(pugl::SizeHint::maxAspect, 16, 9); view.setBackend(pugl::glBackend()); view.setHint(pugl::ViewHint::resizable, opts.resizable); view.setHint(pugl::ViewHint::samples, opts.samples); diff --git a/examples/pugl_cursor_demo.c b/examples/pugl_cursor_demo.c index 8462193..c9839da 100644 --- a/examples/pugl_cursor_demo.c +++ b/examples/pugl_cursor_demo.c @@ -124,9 +124,9 @@ main(int argc, char** argv) PuglView* view = puglNewView(app.world); puglSetWindowTitle(view, "Pugl Cursor Demo"); - puglSetDefaultSize(view, 512, 256); - puglSetMinSize(view, 128, 64); - puglSetMaxSize(view, 512, 256); + puglSetSizeHint(view, PUGL_DEFAULT_SIZE, 512, 256); + puglSetSizeHint(view, PUGL_MIN_SIZE, 128, 64); + puglSetSizeHint(view, PUGL_MAX_SIZE, 512, 256); puglSetBackend(view, puglGlBackend()); puglSetViewHint(view, PUGL_USE_DEBUG_CONTEXT, app.opts.errorChecking); diff --git a/examples/pugl_embed_demo.c b/examples/pugl_embed_demo.c index 085cfa7..66605b7 100644 --- a/examples/pugl_embed_demo.c +++ b/examples/pugl_embed_demo.c @@ -277,10 +277,11 @@ main(int argc, char** argv) puglSetClassName(app.world, "PuglEmbedDemo"); const PuglRect parentFrame = {0, 0, 512, 512}; - puglSetDefaultSize(app.parent, 512, 512); - puglSetMinSize(app.parent, borderWidth * 3, borderWidth * 3); - puglSetMaxSize(app.parent, 1024, 1024); - puglSetAspectRatio(app.parent, 1, 1, 16, 9); + puglSetSizeHint(app.parent, PUGL_DEFAULT_SIZE, 512, 512); + puglSetSizeHint(app.parent, PUGL_MIN_SIZE, 192, 192); + puglSetSizeHint(app.parent, PUGL_MAX_SIZE, 1024, 1024); + puglSetSizeHint(app.parent, PUGL_MIN_ASPECT, 1, 1); + puglSetSizeHint(app.parent, PUGL_MAX_ASPECT, 16, 9); puglSetBackend(app.parent, puglGlBackend()); puglSetViewHint(app.parent, PUGL_USE_DEBUG_CONTEXT, opts.errorChecking); diff --git a/examples/pugl_print_events.c b/examples/pugl_print_events.c index 1bbe33a..3c07873 100644 --- a/examples/pugl_print_events.c +++ b/examples/pugl_print_events.c @@ -43,7 +43,7 @@ main(void) puglSetClassName(app.world, "PuglPrintEvents"); puglSetWindowTitle(app.view, "Pugl Event Printer"); - puglSetDefaultSize(app.view, 512, 512); + puglSetSizeHint(app.view, PUGL_DEFAULT_SIZE, 512, 512); puglSetBackend(app.view, puglStubBackend()); puglSetHandle(app.view, &app); puglSetEventFunc(app.view, onEvent); diff --git a/examples/pugl_shader_demo.c b/examples/pugl_shader_demo.c index db448ca..8f2c2e7 100644 --- a/examples/pugl_shader_demo.c +++ b/examples/pugl_shader_demo.c @@ -45,8 +45,7 @@ # define SHADER_DIR "shaders/" #endif -static const int defaultWidth = 512; -static const int defaultHeight = 512; +static const PuglSpan defaultSpan = 512; static const uintptr_t resizeTimerId = 1u; typedef struct { @@ -180,7 +179,7 @@ makeRects(const size_t numRects) { Rect* rects = (Rect*)calloc(numRects, sizeof(Rect)); for (size_t i = 0; i < numRects; ++i) { - rects[i] = makeRect(i, (float)defaultWidth); + rects[i] = makeRect(i, defaultSpan); } return rects; @@ -262,10 +261,11 @@ setupPugl(PuglTestApp* app) // Set up world and view puglSetClassName(app->world, "PuglShaderDemo"); puglSetWindowTitle(app->view, "Pugl OpenGL Shader Demo"); - puglSetDefaultSize(app->view, defaultWidth, defaultHeight); - puglSetMinSize(app->view, defaultWidth / 4, defaultHeight / 4); - puglSetMaxSize(app->view, defaultWidth * 4, defaultHeight * 4); - puglSetAspectRatio(app->view, 1, 1, 16, 9); + puglSetSizeHint(app->view, PUGL_DEFAULT_SIZE, defaultSpan, defaultSpan); + puglSetSizeHint(app->view, PUGL_MIN_SIZE, 128, 128); + puglSetSizeHint(app->view, PUGL_MAX_SIZE, 2048, 2048); + puglSetSizeHint(app->view, PUGL_MIN_ASPECT, 1, 1); + puglSetSizeHint(app->view, PUGL_MAX_ASPECT, 16, 9); puglSetBackend(app->view, puglGlBackend()); puglSetViewHint(app->view, PUGL_USE_COMPAT_PROFILE, PUGL_FALSE); puglSetViewHint(app->view, PUGL_USE_DEBUG_CONTEXT, app->opts.errorChecking); diff --git a/examples/pugl_vulkan_cpp_demo.cpp b/examples/pugl_vulkan_cpp_demo.cpp index 3f635ba..61c7b80 100644 --- a/examples/pugl_vulkan_cpp_demo.cpp +++ b/examples/pugl_vulkan_cpp_demo.cpp @@ -1708,17 +1708,16 @@ run(const char* const programPath, { PuglVulkanDemo app{programPath, opts, numRects}; - VkResult r = VK_SUCCESS; - const auto width = static_cast<int>(app.extent.width); - const auto height = static_cast<int>(app.extent.height); + VkResult r = VK_SUCCESS; + const auto width = app.extent.width; + const auto height = app.extent.height; // Realize window so we can set up Vulkan app.world.setClassName("PuglVulkanCppDemo"); app.view.setWindowTitle("Pugl Vulkan C++ Demo"); - app.view.setAspectRatio(1, 1, 16, 9); - app.view.setDefaultSize(width, height); - app.view.setMinSize(width / 4, height / 4); - app.view.setMaxSize(width * 4, height * 4); + app.view.setSizeHint(pugl::SizeHint::defaultSize, width, height); + app.view.setSizeHint(pugl::SizeHint::minSize, width / 4, height / 4); + app.view.setSizeHint(pugl::SizeHint::maxSize, width * 4, height * 4); app.view.setBackend(pugl::vulkanBackend()); app.view.setHint(pugl::ViewHint::resizable, opts.resizable); const pugl::Status st = app.view.realize(); diff --git a/examples/pugl_vulkan_demo.c b/examples/pugl_vulkan_demo.c index b7ff146..ec465bb 100644 --- a/examples/pugl_vulkan_demo.c +++ b/examples/pugl_vulkan_demo.c @@ -1036,9 +1036,8 @@ main(int argc, char** argv) memset(&app, 0, sizeof(app)); VulkanState* vk = &app.vk; - const uint32_t defaultWidth = 640; - const uint32_t defaultHeight = 360; - const PuglRect frame = {0, 0, defaultWidth, defaultHeight}; + const PuglSpan defaultWidth = 640; + const PuglSpan defaultHeight = 360; // Parse command line options app.opts = puglParseTestOptions(&argc, &argv); @@ -1065,7 +1064,7 @@ main(int argc, char** argv) // Create window puglSetWindowTitle(app.view, "Pugl Vulkan Demo"); - puglSetFrame(app.view, frame); + puglSetSizeHint(app.view, PUGL_DEFAULT_SIZE, defaultWidth, defaultHeight); puglSetHandle(app.view, &app); puglSetBackend(app.view, puglVulkanBackend()); puglSetViewHint(app.view, PUGL_RESIZABLE, app.opts.resizable); diff --git a/examples/pugl_window_demo.c b/examples/pugl_window_demo.c index 912ccb6..7cb3722 100644 --- a/examples/pugl_window_demo.c +++ b/examples/pugl_window_demo.c @@ -194,9 +194,9 @@ main(int argc, char** argv) puglSetWindowTitle(view, "Pugl Window Demo"); puglSetFrame(view, frame); - puglSetDefaultSize(view, 512, 512); - puglSetMinSize(view, 128, 128); - puglSetMaxSize(view, 2048, 2048); + puglSetSizeHint(view, PUGL_DEFAULT_SIZE, 512, 512); + puglSetSizeHint(view, PUGL_MIN_SIZE, 128, 128); + puglSetSizeHint(view, PUGL_MAX_SIZE, 2048, 2048); puglSetBackend(view, puglGlBackend()); puglSetViewHint(view, PUGL_USE_DEBUG_CONTEXT, opts.errorChecking); diff --git a/include/pugl/pugl.h b/include/pugl/pugl.h index 4abe247..2c00a30 100644 --- a/include/pugl/pugl.h +++ b/include/pugl/pugl.h @@ -60,6 +60,14 @@ PUGL_BEGIN_DECLS */ /** + A pixel span (width or height) within/of a view. + + Due to platform limits, the span of a view in either dimension should be + between 1 and 10000. +*/ +typedef uint16_t PuglSpan; + +/** A rectangle. This is used to describe things like view position and size. Pugl generally @@ -813,6 +821,43 @@ typedef enum { PUGL_TRUE = 1 ///< Explicitly true } PuglViewHintValue; +/** + A hint for configuring/constraining the size of a view. + + The system will attempt to make the view's window adhere to these, but they + are suggestions, not hard constraints. Applications should handle any view + size gracefully. +*/ +typedef enum { + PUGL_DEFAULT_SIZE, ///< Default size + PUGL_MIN_SIZE, ///< Minimum size + PUGL_MAX_SIZE, ///< Maximum size + + /** + Fixed aspect ratio. + + If set, the view's size should be constrained to this aspect ratio. + Mutually exclusive with #PUGL_MIN_ASPECT and #PUGL_MAX_ASPECT. + */ + PUGL_FIXED_ASPECT, + + /** + Minimum aspect ratio. + + If set, the view's size should be constrained to an aspect ratio no lower + than this. Mutually exclusive with #PUGL_FIXED_ASPECT. + */ + PUGL_MIN_ASPECT, + + /** + Maximum aspect ratio. + + If set, the view's size should be constrained to an aspect ratio no higher + than this. Mutually exclusive with #PUGL_FIXED_ASPECT. + */ + PUGL_MAX_ASPECT +} PuglSizeHint; + /// A function called when an event occurs typedef PuglStatus (*PuglEventFunc)(PuglView* view, const PuglEvent* event); @@ -940,64 +985,23 @@ PuglStatus puglSetFrame(PuglView* view, PuglRect frame); /** - Set the default size of the view. - - This should be called before puglResize() to set the default size of the - view, which will be the initial size of the window if this is a top level - view. + Set a size hint for the view. - @return #PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is - not yet realized. -*/ -PUGL_API -PuglStatus -puglSetDefaultSize(PuglView* view, int width, int height); + This can be used to set the default, minimum, and maximum size of a view, as + well as the supported range of aspect ratios. -/** - Set the minimum size of the view. - - If an initial minimum size is known, this should be called before - puglRealize() to avoid stutter, though it can be called afterwards as well. - - @return #PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is - not yet realized. -*/ -PUGL_API -PuglStatus -puglSetMinSize(PuglView* view, int width, int height); - -/** - Set the maximum size of the view. - - If an initial maximum size is known, this should be called before - puglRealize() to avoid stutter, though it can be called afterwards as well. + 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. */ PUGL_API PuglStatus -puglSetMaxSize(PuglView* view, int width, int height); - -/** - Set the view aspect ratio range. - - 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 - currently work on MacOS (the minimum is used), so only setting a fixed - aspect ratio works properly across all platforms. - - If an initial aspect ratio is known, this should be called before - puglRealize() to avoid stutter, though it can be called afterwards as well. - - @return #PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is - not yet realized. -*/ -PUGL_API -PuglStatus -puglSetAspectRatio(PuglView* view, int minX, int minY, int maxX, int maxY); +puglSetSizeHint(PuglView* view, + PuglSizeHint hint, + PuglSpan width, + PuglSpan height); /** @} @@ -1460,7 +1464,7 @@ static inline PUGL_DEPRECATED_BY("puglSetMinSize") void puglInitWindowMinSize(PuglView* view, int width, int height) { - puglSetMinSize(view, width, height); + puglSetSizeHint(view, PUGL_MIN_SIZE, (PuglSpan)width, (PuglSpan)height); } /** @@ -1481,7 +1485,8 @@ puglInitWindowAspectRatio(PuglView* view, int maxX, int maxY) { - puglSetAspectRatio(view, minX, minY, maxX, maxY); + puglSetSizeHint(view, PUGL_MIN_ASPECT, (PuglSpan)minX, (PuglSpan)minY); + puglSetSizeHint(view, PUGL_MAX_ASPECT, (PuglSpan)maxX, (PuglSpan)maxY); } /** @@ -1675,6 +1680,87 @@ PUGL_DEPRECATED_BY("puglHide") PuglStatus puglHideWindow(PuglView* view); +/** + Set the default size of the view. + + This should be called before puglResize() to set the default size of the + view, which will be the initial size of the window if this is a top level + view. + + @return #PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is + not yet realized. +*/ +static inline PUGL_DEPRECATED_BY("puglSetSizeHint") +PuglStatus +puglSetDefaultSize(PuglView* view, int width, int height) +{ + return puglSetSizeHint( + view, PUGL_DEFAULT_SIZE, (PuglSpan)width, (PuglSpan)height); +} + +/** + Set the minimum size of the view. + + If an initial minimum size is known, this should be called before + puglRealize() to avoid stutter, though it can be called afterwards as well. + + @return #PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is + not yet realized. +*/ +static inline PUGL_DEPRECATED_BY("puglSetSizeHint") +PuglStatus +puglSetMinSize(PuglView* view, int width, int height) +{ + return puglSetSizeHint( + view, PUGL_MIN_SIZE, (PuglSpan)width, (PuglSpan)height); +} + +/** + Set the maximum size of the view. + + If an initial maximum size is known, this should be called before + puglRealize() to avoid stutter, though it can be called afterwards as well. + + @return #PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is + not yet realized. +*/ +static inline PUGL_DEPRECATED_BY("puglSetSizeHint") +PuglStatus +puglSetMaxSize(PuglView* view, int width, int height) +{ + return puglSetSizeHint( + view, PUGL_MAX_SIZE, (PuglSpan)width, (PuglSpan)height); +} + +/** + Set the view aspect ratio range. + + 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 + currently work on MacOS (the minimum is used), so only setting a fixed + aspect ratio works properly across all platforms. + + If an initial aspect ratio is known, this should be called before + puglRealize() to avoid stutter, though it can be called afterwards as well. + + @return #PUGL_UNKNOWN_ERROR on failure, but always succeeds if the view is + not yet realized. +*/ +static inline PUGL_DEPRECATED_BY("puglSetSizeHint") +PuglStatus +puglSetAspectRatio(PuglView* view, int minX, int minY, int maxX, int maxY) +{ + const PuglStatus st0 = + puglSetSizeHint(view, PUGL_MIN_ASPECT, (PuglSpan)minX, (PuglSpan)minY); + + const PuglStatus st1 = + puglSetSizeHint(view, PUGL_MAX_ASPECT, (PuglSpan)maxX, (PuglSpan)maxY); + + return st0 ? st0 : st1; +} + #endif // PUGL_DISABLE_DEPRECATED /** diff --git a/src/implementation.c b/src/implementation.c index 166aebd..c3394ce 100644 --- a/src/implementation.c +++ b/src/implementation.c @@ -139,9 +139,9 @@ puglNewView(PuglWorld* const world) return NULL; } - view->world = world; - view->minWidth = 1; - view->minHeight = 1; + view->world = world; + view->sizeHints[PUGL_MIN_SIZE].width = 1; + view->sizeHints[PUGL_MIN_SIZE].height = 1; puglSetDefaultHints(view->hints); @@ -220,12 +220,11 @@ updateViewRect(PuglView* view) - (NSSize)intrinsicContentSize { - if (puglview->defaultWidth || puglview->defaultHeight) { - return sizePoints( - puglview, puglview->defaultWidth, puglview->defaultHeight); - } + const PuglViewSize defaultSize = puglview->sizeHints[PUGL_DEFAULT_SIZE]; - return NSMakeSize(NSViewNoInstrinsicMetric, NSViewNoInstrinsicMetric); + return (defaultSize.width && defaultSize.height) + ? sizePoints(puglview, defaultSize.width, defaultSize.height) + : NSMakeSize(NSViewNoInstrinsicMetric, NSViewNoInstrinsicMetric); } - (BOOL)isFlipped @@ -889,6 +888,47 @@ puglConstraint(const id item, constant:(CGFloat)constant]; } +static PuglStatus +updateSizeHint(PuglView* const view, const PuglSizeHint hint) +{ + const PuglSpan width = view->sizeHints[hint].width; + const PuglSpan height = view->sizeHints[hint].height; + if (!width || !height) { + return PUGL_FAILURE; + } + + switch (hint) { + case PUGL_DEFAULT_SIZE: + break; + + case PUGL_MIN_SIZE: + [view->impl->window setContentMinSize:sizePoints(view, width, height)]; + break; + + case PUGL_MAX_SIZE: + [view->impl->window setContentMaxSize:sizePoints(view, width, height)]; + break; + + case PUGL_FIXED_ASPECT: + [view->impl->window setContentAspectRatio:sizePoints(view, width, height)]; + break; + + case PUGL_MIN_ASPECT: + case PUGL_MAX_ASPECT: + break; + } + + return PUGL_SUCCESS; +} + +static void +updateSizeHints(PuglView* const view) +{ + for (unsigned i = 0u; i <= PUGL_MAX_ASPECT; ++i) { + updateSizeHint(view, (PuglSizeHint)i); + } +} + PuglStatus puglRealize(PuglView* view) { @@ -935,15 +975,16 @@ puglRealize(PuglView* view) } if (view->frame.width == 0.0 && view->frame.height == 0.0) { - if (view->defaultWidth == 0.0 && view->defaultHeight == 0.0) { + const PuglViewSize defaultSize = view->sizeHints[PUGL_DEFAULT_SIZE]; + if (!defaultSize.width || !defaultSize.height) { return PUGL_BAD_CONFIGURATION; } const double screenWidthPx = [screen frame].size.width * scaleFactor; const double screenHeightPx = [screen frame].size.height * scaleFactor; - view->frame.width = view->defaultWidth; - view->frame.height = view->defaultHeight; + view->frame.width = defaultSize.width; + view->frame.height = defaultSize.height; view->frame.x = screenWidthPx / 2.0 - view->frame.width / 2.0; view->frame.y = screenHeightPx / 2.0 - view->frame.height / 2.0; } @@ -966,26 +1007,27 @@ puglRealize(PuglView* view) addConstraint:puglConstraint(impl->wrapperView, NSLayoutAttributeWidth, NSLayoutRelationGreaterThanOrEqual, - view->minWidth)]; + view->sizeHints[PUGL_MIN_SIZE].width)]; [impl->wrapperView addConstraint:puglConstraint(impl->wrapperView, NSLayoutAttributeHeight, NSLayoutRelationGreaterThanOrEqual, - view->minHeight)]; + view->sizeHints[PUGL_MIN_SIZE].height)]; - if (view->maxWidth && view->maxHeight) { + if (view->sizeHints[PUGL_MAX_SIZE].width && + view->sizeHints[PUGL_MAX_SIZE].height) { [impl->wrapperView addConstraint:puglConstraint(impl->wrapperView, NSLayoutAttributeWidth, NSLayoutRelationLessThanOrEqual, - view->maxWidth)]; + view->sizeHints[PUGL_MAX_SIZE].width)]; [impl->wrapperView addConstraint:puglConstraint(impl->wrapperView, NSLayoutAttributeHeight, NSLayoutRelationLessThanOrEqual, - view->maxHeight)]; + view->sizeHints[PUGL_MAX_SIZE].height)]; } // Create draw view to be rendered to @@ -1028,21 +1070,12 @@ puglRealize(PuglView* view) [window setTitle:titleString]; } - if (view->minWidth || view->minHeight) { - [window - setContentMinSize:sizePoints(view, view->minWidth, view->minHeight)]; - } - impl->window = window; - ((NSWindow*)window).delegate = [[PuglWindowDelegate alloc] initWithPuglWindow:window]; - if (view->minAspectX && view->minAspectY) { - [window setContentAspectRatio:sizePoints(view, - view->minAspectX, - view->minAspectY)]; - } + impl->window = window; + updateSizeHints(view); puglSetFrame(view, view->frame); [window setContentView:impl->wrapperView]; @@ -1358,60 +1391,19 @@ puglSetFrame(PuglView* view, const PuglRect frame) } PuglStatus -puglSetDefaultSize(PuglView* const view, const int width, const int height) -{ - view->defaultWidth = width; - view->defaultHeight = height; - return PUGL_SUCCESS; -} - -PuglStatus -puglSetMinSize(PuglView* const view, const int width, const int height) -{ - view->minWidth = width; - view->minHeight = height; - - if (view->impl->window && (view->minWidth || view->minHeight)) { - [view->impl->window - setContentMinSize:sizePoints(view, view->minWidth, view->minHeight)]; - } - - return PUGL_SUCCESS; -} - -PuglStatus -puglSetMaxSize(PuglView* const view, const int width, const int height) +puglSetSizeHint(PuglView* const view, + const PuglSizeHint hint, + const PuglSpan width, + const PuglSpan height) { - view->maxWidth = width; - view->maxHeight = height; - - if (view->impl->window && (view->maxWidth || view->maxHeight)) { - [view->impl->window - setContentMaxSize:sizePoints(view, view->maxWidth, view->maxHeight)]; + if ((unsigned)hint > (unsigned)PUGL_MAX_ASPECT) { + return PUGL_BAD_PARAMETER; } - return PUGL_SUCCESS; -} + view->sizeHints[hint].width = width; + view->sizeHints[hint].height = height; -PuglStatus -puglSetAspectRatio(PuglView* const view, - const int minX, - const int minY, - const int maxX, - const int maxY) -{ - view->minAspectX = minX; - view->minAspectY = minY; - view->maxAspectX = maxX; - view->maxAspectY = maxY; - - if (view->impl->window && view->minAspectX && view->minAspectY) { - [view->impl->window setContentAspectRatio:sizePoints(view, - view->minAspectX, - view->minAspectY)]; - } - - return PUGL_SUCCESS; + return view->impl->window ? updateSizeHint(view, hint) : PUGL_SUCCESS; } PuglStatus diff --git a/src/types.h b/src/types.h index 67e9eef..0187dad 100644 --- a/src/types.h +++ b/src/types.h @@ -21,6 +21,12 @@ typedef struct PuglInternalsImpl PuglInternals; /// View hints typedef int PuglHints[PUGL_NUM_VIEW_HINTS]; +/// View size (both X and Y coordinates) +typedef struct { + PuglSpan width; + PuglSpan height; +} PuglViewSize; + /// Blob of arbitrary data typedef struct { void* data; ///< Dynamically allocated data @@ -41,16 +47,7 @@ struct PuglViewImpl { PuglRect frame; PuglConfigureEvent lastConfigure; PuglHints hints; - int defaultWidth; - int defaultHeight; - int minWidth; - int minHeight; - int maxWidth; - int maxHeight; - int minAspectX; - int minAspectY; - int maxAspectX; - int maxAspectY; + PuglViewSize sizeHints[(unsigned)PUGL_MAX_ASPECT + 1u]; bool visible; }; @@ -522,8 +522,11 @@ constrainAspect(const PuglView* const view, RECT* const size, const WPARAM wParam) { - const float minA = (float)view->minAspectX / (float)view->minAspectY; - const float maxA = (float)view->maxAspectX / (float)view->maxAspectY; + const PuglViewSize minAspect = view->sizeHints[PUGL_MIN_ASPECT]; + const PuglViewSize maxAspect = view->sizeHints[PUGL_MAX_ASPECT]; + + const float minA = (float)minAspect.width / (float)minAspect.height; + const float maxA = (float)maxAspect.width / (float)maxAspect.height; const float w = (float)(size->right - size->left); const float h = (float)(size->bottom - size->top); const float a = w / h; @@ -602,7 +605,7 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) } break; case WM_SIZING: - if (view->minAspectX) { + if (view->sizeHints[PUGL_MIN_ASPECT].width) { constrainAspect(view, (RECT*)lParam, wParam); return TRUE; } @@ -624,11 +627,12 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) break; case WM_GETMINMAXINFO: mmi = (MINMAXINFO*)lParam; - mmi->ptMinTrackSize.x = view->minWidth; - mmi->ptMinTrackSize.y = view->minHeight; - if (view->maxWidth > 0 && view->maxHeight > 0) { - mmi->ptMaxTrackSize.x = view->maxWidth; - mmi->ptMaxTrackSize.y = view->maxHeight; + mmi->ptMinTrackSize.x = view->sizeHints[PUGL_MIN_SIZE].width; + mmi->ptMinTrackSize.y = view->sizeHints[PUGL_MIN_SIZE].height; + if (view->sizeHints[PUGL_MAX_SIZE].width && + view->sizeHints[PUGL_MAX_SIZE].height) { + mmi->ptMaxTrackSize.x = view->sizeHints[PUGL_MAX_SIZE].width; + mmi->ptMaxTrackSize.y = view->sizeHints[PUGL_MAX_SIZE].height; } break; case WM_PAINT: @@ -1008,40 +1012,17 @@ puglSetFrame(PuglView* view, const PuglRect frame) } PuglStatus -puglSetDefaultSize(PuglView* const view, const int width, const int height) +puglSetSizeHint(PuglView* const view, + const PuglSizeHint hint, + const PuglSpan width, + const PuglSpan height) { - view->defaultWidth = width; - view->defaultHeight = height; - return PUGL_SUCCESS; -} - -PuglStatus -puglSetMinSize(PuglView* const view, const int width, const int height) -{ - view->minWidth = width; - view->minHeight = height; - return PUGL_SUCCESS; -} - -PuglStatus -puglSetMaxSize(PuglView* const view, const int width, const int height) -{ - view->maxWidth = width; - view->maxHeight = height; - return PUGL_SUCCESS; -} + if ((unsigned)hint > (unsigned)PUGL_MAX_ASPECT || width < 0 || height < 0) { + return PUGL_BAD_PARAMETER; + } -PuglStatus -puglSetAspectRatio(PuglView* const view, - const int minX, - const int minY, - const int maxX, - const int maxY) -{ - view->minAspectX = minX; - view->minAspectY = minY; - view->maxAspectX = maxX; - view->maxAspectY = maxY; + view->sizeHints[hint].width = width; + view->sizeHints[hint].height = height; return PUGL_SUCCESS; } @@ -1206,7 +1187,8 @@ puglWinCreateWindow(PuglView* const view, const unsigned winExFlags = puglWinGetWindowExFlags(view); if (view->frame.width <= 0.0 && view->frame.height <= 0.0) { - if (view->defaultWidth <= 0.0 && view->defaultHeight <= 0.0) { + const PuglViewSize defaultSize = view->sizeHints[PUGL_DEFAULT_SIZE]; + if (!defaultSize.width || !defaultSize.height) { return PUGL_BAD_CONFIGURATION; } @@ -1216,10 +1198,10 @@ puglWinCreateWindow(PuglView* const view, const int screenWidth = desktopRect.right - desktopRect.left; const int screenHeight = desktopRect.bottom - desktopRect.top; - view->frame.width = view->defaultWidth; - view->frame.height = view->defaultHeight; - view->frame.x = screenWidth / 2.0 - view->frame.width / 2.0; - view->frame.y = screenHeight / 2.0 - view->frame.height / 2.0; + view->frame.width = defaultSize.width; + view->frame.height = defaultSize.height; + view->frame.x = (screenWidth - view->frame.width) / 2.0; + view->frame.y = (screenHeight - view->frame.height) / 2.0; } // The meaning of "parent" depends on the window type (WS_CHILD) @@ -224,30 +224,45 @@ updateSizeHints(const PuglView* const view) sizeHints.max_width = (int)view->frame.width; sizeHints.max_height = (int)view->frame.height; } else { - if (view->defaultWidth || view->defaultHeight) { + const PuglViewSize defaultSize = view->sizeHints[PUGL_DEFAULT_SIZE]; + if (defaultSize.width && defaultSize.height) { sizeHints.flags |= PBaseSize; - sizeHints.base_width = view->defaultWidth; - sizeHints.base_height = view->defaultHeight; + sizeHints.base_width = defaultSize.width; + sizeHints.base_height = defaultSize.height; } - if (view->minWidth || view->minHeight) { + const PuglViewSize minSize = view->sizeHints[PUGL_MIN_SIZE]; + if (minSize.width && minSize.height) { sizeHints.flags |= PMinSize; - sizeHints.min_width = view->minWidth; - sizeHints.min_height = view->minHeight; + sizeHints.min_width = minSize.width; + sizeHints.min_height = minSize.height; } - if (view->maxWidth || view->maxHeight) { + const PuglViewSize maxSize = view->sizeHints[PUGL_MAX_SIZE]; + if (maxSize.width && maxSize.height) { sizeHints.flags |= PMaxSize; - sizeHints.max_width = view->maxWidth; - sizeHints.max_height = view->maxHeight; + sizeHints.max_width = maxSize.width; + sizeHints.max_height = maxSize.height; } - if (view->minAspectX) { + const PuglViewSize minAspect = view->sizeHints[PUGL_MIN_ASPECT]; + const PuglViewSize maxAspect = view->sizeHints[PUGL_MAX_ASPECT]; + if (minAspect.width && minAspect.height && maxAspect.width && + maxAspect.height) { sizeHints.flags |= PAspect; - sizeHints.min_aspect.x = view->minAspectX; - sizeHints.min_aspect.y = view->minAspectY; - sizeHints.max_aspect.x = view->maxAspectX; - sizeHints.max_aspect.y = view->maxAspectY; + sizeHints.min_aspect.x = minAspect.width; + sizeHints.min_aspect.y = minAspect.height; + sizeHints.max_aspect.x = maxAspect.width; + sizeHints.max_aspect.y = maxAspect.height; + } + + const PuglViewSize fixedAspect = view->sizeHints[PUGL_FIXED_ASPECT]; + if (fixedAspect.width && fixedAspect.height) { + sizeHints.flags |= PAspect; + sizeHints.min_aspect.x = fixedAspect.width; + sizeHints.min_aspect.y = fixedAspect.height; + sizeHints.max_aspect.x = fixedAspect.width; + sizeHints.max_aspect.y = fixedAspect.height; } } @@ -314,12 +329,13 @@ puglRealize(PuglView* const view) // Set the size to the default if it has not already been set if (view->frame.width <= 0.0 && view->frame.height <= 0.0) { - if (view->defaultWidth <= 0.0 || view->defaultHeight <= 0.0) { + const PuglViewSize defaultSize = view->sizeHints[PUGL_DEFAULT_SIZE]; + if (!defaultSize.width || !defaultSize.height) { return PUGL_BAD_CONFIGURATION; } - view->frame.width = view->defaultWidth; - view->frame.height = view->defaultHeight; + view->frame.width = defaultSize.width; + view->frame.height = defaultSize.height; } // Center top-level windows if a position has not been set @@ -1366,40 +1382,17 @@ puglSetFrame(PuglView* const view, const PuglRect frame) } PuglStatus -puglSetDefaultSize(PuglView* const view, const int width, const int height) -{ - view->defaultWidth = width; - view->defaultHeight = height; - return updateSizeHints(view); -} - -PuglStatus -puglSetMinSize(PuglView* const view, const int width, const int height) +puglSetSizeHint(PuglView* const view, + const PuglSizeHint hint, + const PuglSpan width, + const PuglSpan height) { - view->minWidth = width; - view->minHeight = height; - return updateSizeHints(view); -} - -PuglStatus -puglSetMaxSize(PuglView* const view, const int width, const int height) -{ - view->maxWidth = width; - view->maxHeight = height; - return updateSizeHints(view); -} + if ((unsigned)hint > (unsigned)PUGL_MAX_ASPECT) { + return PUGL_BAD_PARAMETER; + } -PuglStatus -puglSetAspectRatio(PuglView* const view, - const int minX, - const int minY, - const int maxX, - const int maxY) -{ - view->minAspectX = minX; - view->minAspectY = minY; - view->maxAspectX = maxX; - view->maxAspectY = maxY; + view->sizeHints[hint].width = width; + view->sizeHints[hint].height = height; return updateSizeHints(view); } diff --git a/test/test_cairo.c b/test/test_cairo.c index 5d2aab8..a9a36db 100644 --- a/test/test_cairo.c +++ b/test/test_cairo.c @@ -65,7 +65,7 @@ main(int argc, char** argv) puglSetHandle(test.view, &test); puglSetBackend(test.view, puglCairoBackend()); puglSetEventFunc(test.view, onEvent); - puglSetDefaultSize(test.view, 512, 512); + puglSetSizeHint(test.view, PUGL_DEFAULT_SIZE, 512, 512); puglShow(test.view); // Drive event loop until the view gets exposed diff --git a/test/test_gl.c b/test/test_gl.c index 3fe546b..da84c1a 100644 --- a/test/test_gl.c +++ b/test/test_gl.c @@ -84,7 +84,7 @@ main(int argc, char** argv) puglSetHandle(test.view, &test); puglSetBackend(test.view, puglGlBackend()); puglSetEventFunc(test.view, onEvent); - puglSetDefaultSize(test.view, 512, 512); + puglSetSizeHint(test.view, PUGL_DEFAULT_SIZE, 512, 512); puglShow(test.view); // Enter OpenGL context as if setting things up diff --git a/test/test_gl_free_unrealized.c b/test/test_gl_free_unrealized.c index 783ffb8..04a23db 100644 --- a/test/test_gl_free_unrealized.c +++ b/test/test_gl_free_unrealized.c @@ -49,7 +49,7 @@ main(int argc, char** argv) puglSetBackend(test.view, puglGlBackend()); puglSetHandle(test.view, &test); puglSetEventFunc(test.view, onEvent); - puglSetDefaultSize(test.view, 512, 512); + puglSetSizeHint(test.view, PUGL_DEFAULT_SIZE, 512, 512); assert(!puglGetVisible(test.view)); diff --git a/test/test_gl_hints.c b/test/test_gl_hints.c index 701dd77..7e91035 100644 --- a/test/test_gl_hints.c +++ b/test/test_gl_hints.c @@ -34,7 +34,7 @@ main(void) puglSetWindowTitle(view, "Pugl OpenGL Hints Test"); puglSetBackend(view, puglGlBackend()); puglSetEventFunc(view, onEvent); - puglSetDefaultSize(view, 512, 512); + puglSetSizeHint(view, PUGL_DEFAULT_SIZE, 512, 512); // Check invalid cases assert(puglSetViewHint(view, PUGL_USE_COMPAT_PROFILE, PUGL_DONT_CARE) == diff --git a/test/test_local_copy_paste.c b/test/test_local_copy_paste.c index a4350f0..f5c75c4 100644 --- a/test/test_local_copy_paste.c +++ b/test/test_local_copy_paste.c @@ -94,7 +94,7 @@ main(int argc, char** argv) puglSetBackend(app.view, puglStubBackend()); puglSetHandle(app.view, &app); puglSetEventFunc(app.view, onEvent); - puglSetDefaultSize(app.view, 512, 512); + puglSetSizeHint(app.view, PUGL_DEFAULT_SIZE, 512, 512); // Create and show window assert(!puglRealize(app.view)); diff --git a/test/test_realize.c b/test/test_realize.c index d26d866..50eba46 100644 --- a/test/test_realize.c +++ b/test/test_realize.c @@ -68,7 +68,7 @@ main(int argc, char** argv) puglSetBackend(test.view, puglStubBackend()); puglSetHandle(test.view, &test); puglSetEventFunc(test.view, onEvent); - puglSetDefaultSize(test.view, 512, 512); + puglSetSizeHint(test.view, PUGL_DEFAULT_SIZE, 512, 512); // Create initially invisible window assert(!puglRealize(test.view)); diff --git a/test/test_redisplay.c b/test/test_redisplay.c index 801393e..afe89dc 100644 --- a/test/test_redisplay.c +++ b/test/test_redisplay.c @@ -113,7 +113,7 @@ main(int argc, char** argv) puglSetBackend(test.view, puglStubBackend()); puglSetHandle(test.view, &test); puglSetEventFunc(test.view, onEvent); - puglSetDefaultSize(test.view, 512, 512); + puglSetSizeHint(test.view, PUGL_DEFAULT_SIZE, 512, 512); // Create and show window assert(!puglRealize(test.view)); diff --git a/test/test_remote_copy_paste.c b/test/test_remote_copy_paste.c index aeba3dc..2ee90f7 100644 --- a/test/test_remote_copy_paste.c +++ b/test/test_remote_copy_paste.c @@ -131,7 +131,7 @@ main(int argc, char** argv) puglSetBackend(app.copierView, puglStubBackend()); puglSetHandle(app.copierView, &app); puglSetEventFunc(app.copierView, onCopierEvent); - puglSetDefaultSize(app.copierView, 256, 256); + puglSetSizeHint(app.copierView, PUGL_DEFAULT_SIZE, 256, 256); // Set up paster view app.pasterView = puglNewView(app.world); @@ -140,7 +140,7 @@ main(int argc, char** argv) puglSetBackend(app.pasterView, puglStubBackend()); puglSetHandle(app.pasterView, &app); puglSetEventFunc(app.pasterView, onPasterEvent); - puglSetDefaultSize(app.pasterView, 256, 256); + puglSetSizeHint(app.pasterView, PUGL_DEFAULT_SIZE, 256, 256); // Create and show both views assert(!puglShow(app.copierView)); diff --git a/test/test_show_hide.c b/test/test_show_hide.c index 32efe19..bfcb035 100644 --- a/test/test_show_hide.c +++ b/test/test_show_hide.c @@ -103,7 +103,7 @@ main(int argc, char** argv) puglSetBackend(test.view, puglStubBackend()); puglSetHandle(test.view, &test); puglSetEventFunc(test.view, onEvent); - puglSetDefaultSize(test.view, 512, 512); + puglSetSizeHint(test.view, PUGL_DEFAULT_SIZE, 512, 512); // Create initially invisible window assert(!puglRealize(test.view)); diff --git a/test/test_size.c b/test/test_size.c index 862eba5..048bfa5 100644 --- a/test/test_size.c +++ b/test/test_size.c @@ -69,9 +69,9 @@ onEvent(PuglView* view, const PuglEvent* event) int main(int argc, char** argv) { - static const int minSize = 256; - static const int defaultSize = 512; - static const int maxSize = 1024; + static const PuglSpan minSize = 256; + static const PuglSpan defaultSize = 512; + static const PuglSpan maxSize = 1024; PuglTest test = {puglNewWorld(PUGL_PROGRAM, 0), NULL, @@ -87,10 +87,11 @@ main(int argc, char** argv) puglSetHandle(test.view, &test); puglSetEventFunc(test.view, onEvent); puglSetViewHint(test.view, PUGL_RESIZABLE, PUGL_TRUE); - puglSetMinSize(test.view, minSize, minSize); - puglSetDefaultSize(test.view, defaultSize, defaultSize); - puglSetMaxSize(test.view, maxSize, maxSize); - puglSetAspectRatio(test.view, 1, 1, 1, 1); + puglSetSizeHint(test.view, PUGL_DEFAULT_SIZE, defaultSize, defaultSize); + puglSetSizeHint(test.view, PUGL_MIN_SIZE, minSize, minSize); + puglSetSizeHint(test.view, PUGL_MAX_SIZE, maxSize, maxSize); + puglSetSizeHint(test.view, PUGL_MIN_ASPECT, 1, 1); + puglSetSizeHint(test.view, PUGL_MAX_ASPECT, 1, 1); // Create and show window assert(!puglRealize(test.view)); diff --git a/test/test_stub.c b/test/test_stub.c index 308aae3..8ab2c15 100644 --- a/test/test_stub.c +++ b/test/test_stub.c @@ -51,7 +51,7 @@ main(int argc, char** argv) puglSetHandle(test.view, &test); puglSetBackend(test.view, puglStubBackend()); puglSetEventFunc(test.view, onEvent); - puglSetDefaultSize(test.view, 512, 512); + puglSetSizeHint(test.view, PUGL_DEFAULT_SIZE, 512, 512); puglShow(test.view); // Drive event loop until the view gets exposed diff --git a/test/test_stub_hints.c b/test/test_stub_hints.c index f45bacc..12a848b 100644 --- a/test/test_stub_hints.c +++ b/test/test_stub_hints.c @@ -34,7 +34,7 @@ main(void) puglSetWindowTitle(view, "Pugl Stub Hints Test"); puglSetBackend(view, puglStubBackend()); puglSetEventFunc(view, onEvent); - puglSetDefaultSize(view, 512, 512); + puglSetSizeHint(view, PUGL_DEFAULT_SIZE, 512, 512); // Check invalid cases assert(puglSetViewHint(view, (PuglViewHint)9999, 0) == PUGL_BAD_PARAMETER); diff --git a/test/test_timer.c b/test/test_timer.c index 70e6e3b..401e4d5 100644 --- a/test/test_timer.c +++ b/test/test_timer.c @@ -111,7 +111,7 @@ main(int argc, char** argv) puglSetBackend(test.view, puglStubBackend()); puglSetHandle(test.view, &test); puglSetEventFunc(test.view, onEvent); - puglSetDefaultSize(test.view, 512, 512); + puglSetSizeHint(test.view, PUGL_DEFAULT_SIZE, 512, 512); // Create and show window assert(!puglRealize(test.view)); diff --git a/test/test_update.c b/test/test_update.c index 4fb6ac1..381e34b 100644 --- a/test/test_update.c +++ b/test/test_update.c @@ -89,7 +89,7 @@ main(int argc, char** argv) puglSetBackend(test.view, puglStubBackend()); puglSetHandle(test.view, &test); puglSetEventFunc(test.view, onEvent); - puglSetDefaultSize(test.view, 512, 512); + puglSetSizeHint(test.view, PUGL_DEFAULT_SIZE, 512, 512); // Create and show window assert(!puglRealize(test.view)); diff --git a/test/test_view.c b/test/test_view.c index 04cd2c1..e9a954c 100644 --- a/test/test_view.c +++ b/test/test_view.c @@ -70,7 +70,7 @@ main(int argc, char** argv) puglSetBackend(test.view, puglStubBackend()); puglSetHandle(test.view, &test); puglSetEventFunc(test.view, onEvent); - puglSetDefaultSize(test.view, 512, 512); + puglSetSizeHint(test.view, PUGL_DEFAULT_SIZE, 512, 512); // Create and show window assert(!puglRealize(test.view)); diff --git a/test/test_vulkan.c b/test/test_vulkan.c index 0a364f3..77921b4 100644 --- a/test/test_vulkan.c +++ b/test/test_vulkan.c @@ -171,7 +171,7 @@ main(int argc, char** argv) puglSetHandle(test.view, &test); puglSetBackend(test.view, puglVulkanBackend()); puglSetEventFunc(test.view, onEvent); - puglSetDefaultSize(test.view, 512, 512); + puglSetSizeHint(test.view, PUGL_DEFAULT_SIZE, 512, 512); assert(!puglRealize(test.view)); // Create Vulkan surface for window |