aboutsummaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2023-01-07 19:27:14 -0500
committerDavid Robillard <d@drobilla.net>2023-01-07 20:27:35 -0500
commit4ad8621ac1d94c8e9cf88f83c46a3a70cd91212b (patch)
tree63307cb14d43c7391b34f94ca0e532d8e9e01a09 /examples
parent677e13dcbb5b64ce85093b9ea5c14025964e35b9 (diff)
downloadpugl-4ad8621ac1d94c8e9cf88f83c46a3a70cd91212b.tar.gz
pugl-4ad8621ac1d94c8e9cf88f83c46a3a70cd91212b.tar.bz2
pugl-4ad8621ac1d94c8e9cf88f83c46a3a70cd91212b.zip
Add support for special view types and styles
Diffstat (limited to 'examples')
-rw-r--r--examples/meson.build4
-rw-r--r--examples/pugl_embed_demo.c3
-rw-r--r--examples/pugl_management_demo.app/MacOS/meson.build11
-rw-r--r--examples/pugl_management_demo.app/meson.build11
-rw-r--r--examples/pugl_management_demo.c262
-rw-r--r--examples/pugl_vulkan_cpp_demo.cpp3
6 files changed, 290 insertions, 4 deletions
diff --git a/examples/meson.build b/examples/meson.build
index 70a2384..2b4e5f1 100644
--- a/examples/meson.build
+++ b/examples/meson.build
@@ -18,7 +18,8 @@ gl_examples = [
]
cairo_examples = [
- 'pugl_cairo_demo.c'
+ 'pugl_cairo_demo.c',
+ 'pugl_management_demo.c',
]
vulkan_examples = [
@@ -89,6 +90,7 @@ if host_machine.system() == 'darwin'
if cairo_dep.found()
subdir('pugl_cairo_demo.app')
+ subdir('pugl_management_demo.app')
endif
if opengl_dep.found()
diff --git a/examples/pugl_embed_demo.c b/examples/pugl_embed_demo.c
index 94310a5..59d8e2b 100644
--- a/examples/pugl_embed_demo.c
+++ b/examples/pugl_embed_demo.c
@@ -319,7 +319,8 @@ main(int argc, char** argv)
++framesDrawn;
if (!requestedAttention && thisTime > 5.0) {
- puglRequestAttention(app.parent);
+ puglSetViewStyle(
+ app.parent, puglGetViewStyle(app.parent) | PUGL_VIEW_STYLE_DEMANDING);
requestedAttention = true;
}
diff --git a/examples/pugl_management_demo.app/MacOS/meson.build b/examples/pugl_management_demo.app/MacOS/meson.build
new file mode 100644
index 0000000..1ad7b21
--- /dev/null
+++ b/examples/pugl_management_demo.app/MacOS/meson.build
@@ -0,0 +1,11 @@
+# Copyright 2021-2023 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+executable(
+ 'pugl_management_demo',
+ ['../../pugl_management_demo.c'],
+ c_args: example_defines + example_c_args + cairo_args,
+ cpp_args: example_defines + example_cpp_args,
+ dependencies: [pugl_dep, cairo_backend_dep],
+ include_directories: include_directories('../../..'),
+)
diff --git a/examples/pugl_management_demo.app/meson.build b/examples/pugl_management_demo.app/meson.build
new file mode 100644
index 0000000..380e38d
--- /dev/null
+++ b/examples/pugl_management_demo.app/meson.build
@@ -0,0 +1,11 @@
+# Copyright 2021-2023 David Robillard <d@drobilla.net>
+# SPDX-License-Identifier: 0BSD OR ISC
+
+config = configuration_data()
+config.set('NAME', 'pugl_management_demo')
+
+info_plist = configure_file(configuration: config,
+ input: files('../../resources/Info.plist.in'),
+ output: 'Info.plist')
+
+subdir('MacOS')
diff --git a/examples/pugl_management_demo.c b/examples/pugl_management_demo.c
new file mode 100644
index 0000000..6a62668
--- /dev/null
+++ b/examples/pugl_management_demo.c
@@ -0,0 +1,262 @@
+// Copyright 2012-2023 David Robillard <d@drobilla.net>
+// SPDX-License-Identifier: ISC
+
+/*
+ A demonstration of window types, states, and management.
+*/
+
+#include "test/test_utils.h"
+
+#include "pugl/cairo.h"
+#include "pugl/pugl.h"
+
+#include <cairo.h>
+
+#include <stdbool.h>
+#include <stdio.h>
+
+typedef struct {
+ PuglView* view;
+ const char* label;
+} LabeledView;
+
+typedef struct {
+ PuglWorld* world;
+ LabeledView mainView;
+ LabeledView dialogView;
+ bool quit;
+ bool verbose;
+} DemoApp;
+
+static PuglStatus
+onCommonEvent(PuglView* view, const PuglEvent* event);
+
+static PuglStatus
+onMainEvent(PuglView* view, const PuglEvent* event);
+
+static PuglStatus
+onExpose(PuglView* const view, const PuglExposeEvent* const event)
+{
+ PuglWorld* const world = puglGetWorld(view);
+ DemoApp* const app = (DemoApp*)puglGetWorldHandle(world);
+ const PuglRect frame = puglGetFrame(view);
+ const PuglViewStyleFlags style = puglGetViewStyle(view);
+ const PuglCoord cx = (PuglCoord)(frame.width / 2U);
+ const PuglCoord cy = (PuglCoord)(frame.height / 2U);
+ cairo_t* const cr = (cairo_t*)puglGetContext(view);
+
+ // Clip to expose region
+ cairo_rectangle(cr, event->x, event->y, event->width, event->height);
+ cairo_clip_preserve(cr);
+
+ // Draw background
+ cairo_set_source_rgb(cr, 0.2, 0.2, 0.2);
+ cairo_set_line_width(cr, 4.0);
+ cairo_fill(cr);
+
+ // Set up text renering
+ char buf[128] = {0};
+ cairo_text_extents_t extents = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
+ cairo_set_font_size(cr, 32.0);
+
+ // Draw time label
+ snprintf(buf, sizeof(buf), "Draw time: %g", puglGetTime(world));
+ cairo_text_extents(cr, buf, &extents);
+ cairo_move_to(cr, cx - extents.width / 2.0, cy + extents.height / 2.0 - 48.0);
+ cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
+ cairo_show_text(cr, buf);
+
+ // Draw style label
+ snprintf(buf,
+ sizeof(buf),
+ "Style:%s%s%s%s%s%s%s%s%s",
+ style & PUGL_VIEW_STYLE_MODAL ? " modal" : "",
+ style & PUGL_VIEW_STYLE_TALL ? " tall" : "",
+ style & PUGL_VIEW_STYLE_WIDE ? " wide" : "",
+ style & PUGL_VIEW_STYLE_HIDDEN ? " hidden" : "",
+ style & PUGL_VIEW_STYLE_FULLSCREEN ? " fullscreen" : "",
+ style & PUGL_VIEW_STYLE_ABOVE ? " above" : "",
+ style & PUGL_VIEW_STYLE_BELOW ? " below" : "",
+ style & PUGL_VIEW_STYLE_DEMANDING ? " demanding" : "",
+ style & PUGL_VIEW_STYLE_RESIZING ? " resizing" : "");
+ cairo_text_extents(cr, buf, &extents);
+ cairo_move_to(cr, cx - extents.width / 2.0, cy + extents.height / 2.0);
+ cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
+ cairo_show_text(cr, buf);
+
+ if (view == app->mainView.view) {
+ // Draw keyboard help label
+ snprintf(buf, sizeof(buf), "Keys: Space T W H M F A B D Q");
+ cairo_text_extents(cr, buf, &extents);
+ cairo_move_to(
+ cr, cx - extents.width / 2.0, cy + extents.height / 2.0 + 48.0);
+ cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
+ cairo_show_text(cr, buf);
+ }
+
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+toggleDialog(DemoApp* const app)
+{
+ if (app->dialogView.view && puglGetVisible(app->dialogView.view)) {
+ return puglUnrealize(app->dialogView.view);
+ }
+
+ if (!app->dialogView.view) {
+ app->dialogView.view = puglNewView(app->world);
+
+ puglSetBackend(app->dialogView.view, puglCairoBackend());
+ puglSetEventFunc(app->dialogView.view, onCommonEvent);
+ puglSetHandle(app->dialogView.view, &app->dialogView);
+ puglSetTransientParent(app->dialogView.view,
+ puglGetNativeView(app->mainView.view));
+ puglSetSizeHint(app->dialogView.view, PUGL_DEFAULT_SIZE, 320, 240);
+ puglSetSizeHint(app->dialogView.view, PUGL_MIN_SIZE, 160, 120);
+ puglSetViewHint(app->dialogView.view, PUGL_IGNORE_KEY_REPEAT, true);
+ puglSetViewHint(app->dialogView.view, PUGL_RESIZABLE, true);
+ puglSetViewHint(
+ app->dialogView.view, PUGL_VIEW_TYPE, PUGL_VIEW_TYPE_DIALOG);
+ puglSetWindowTitle(app->dialogView.view, "Dialog");
+ }
+
+ return puglShow(app->dialogView.view);
+}
+
+static PuglStatus
+onKeyPress(PuglView* view, const PuglKeyEvent* event)
+{
+ PuglWorld* const world = puglGetWorld(view);
+ DemoApp* const app = (DemoApp*)puglGetWorldHandle(world);
+ const PuglViewStyleFlags flags = puglGetViewStyle(view);
+
+ switch (event->key) {
+ case ' ':
+ toggleDialog(app);
+ break;
+ case 't':
+ return puglSetViewStyle(view, flags ^ PUGL_VIEW_STYLE_TALL);
+ case 'w':
+ return puglSetViewStyle(view, flags ^ PUGL_VIEW_STYLE_WIDE);
+ case 'h':
+ return puglSetViewStyle(view, flags ^ PUGL_VIEW_STYLE_HIDDEN);
+ case 'm':
+ if ((flags & PUGL_VIEW_STYLE_TALL) && (flags & PUGL_VIEW_STYLE_WIDE)) {
+ return puglSetViewStyle(
+ view, flags & ~(PUGL_VIEW_STYLE_TALL | PUGL_VIEW_STYLE_WIDE));
+ }
+
+ return puglSetViewStyle(
+ view, flags | PUGL_VIEW_STYLE_TALL | PUGL_VIEW_STYLE_WIDE);
+ case 'f':
+ return puglSetViewStyle(view, flags ^ PUGL_VIEW_STYLE_FULLSCREEN);
+ case 'a':
+ return puglSetViewStyle(view, flags ^ PUGL_VIEW_STYLE_ABOVE);
+ case 'b':
+ return puglSetViewStyle(view, flags ^ PUGL_VIEW_STYLE_BELOW);
+ case 'd':
+ return puglSetViewStyle(view, flags ^ PUGL_VIEW_STYLE_DEMANDING);
+ case 'q':
+ case PUGL_KEY_ESCAPE:
+ app->quit = true;
+ break;
+ }
+
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+onCommonEvent(PuglView* view, const PuglEvent* const event)
+{
+ PuglWorld* const world = puglGetWorld(view);
+ DemoApp* const app = (DemoApp*)puglGetWorldHandle(world);
+ LabeledView* const data = (LabeledView*)puglGetHandle(view);
+
+ const char* const prefix = data->label;
+ printEvent(event, prefix, app->verbose);
+
+ switch (event->type) {
+ case PUGL_CLOSE:
+ if (view == app->dialogView.view) {
+ puglUnrealize(app->dialogView.view);
+ }
+ break;
+ case PUGL_CONFIGURE:
+ return puglPostRedisplay(view);
+ case PUGL_EXPOSE:
+ return onExpose(view, &event->expose);
+ case PUGL_KEY_PRESS:
+ return onKeyPress(view, &event->key);
+ default:
+ break;
+ }
+
+ return PUGL_SUCCESS;
+}
+
+static PuglStatus
+onMainEvent(PuglView* view, const PuglEvent* const event)
+{
+ PuglWorld* const world = puglGetWorld(view);
+ DemoApp* const app = (DemoApp*)puglGetWorldHandle(world);
+
+ switch (event->type) {
+ case PUGL_CLOSE:
+ app->quit = true;
+ return PUGL_SUCCESS;
+ default:
+ break;
+ }
+
+ return onCommonEvent(view, event);
+}
+
+int
+main(int argc, char** argv)
+{
+ DemoApp app = {0};
+
+ const PuglTestOptions opts = puglParseTestOptions(&argc, &argv);
+ if (opts.help) {
+ puglPrintTestUsage(argv[0], "");
+ return 1;
+ }
+
+ app.verbose = opts.verbose;
+
+ app.world = puglNewWorld(PUGL_PROGRAM, 0);
+
+ puglSetWorldHandle(app.world, &app);
+ puglSetClassName(app.world, "PuglDemoApp");
+
+ app.mainView.view = puglNewView(app.world);
+ app.mainView.label = "Main: ";
+ app.dialogView.label = "Dialog: ";
+
+ // Set up main view
+ puglSetBackend(app.mainView.view, puglCairoBackend());
+ puglSetEventFunc(app.mainView.view, onMainEvent);
+ puglSetHandle(app.mainView.view, &app.mainView);
+ puglSetSizeHint(app.mainView.view, PUGL_DEFAULT_SIZE, 640, 480);
+ puglSetSizeHint(app.mainView.view, PUGL_MIN_SIZE, 320, 240);
+ puglSetViewHint(app.mainView.view, PUGL_IGNORE_KEY_REPEAT, true);
+ puglSetViewHint(app.mainView.view, PUGL_RESIZABLE, true);
+ puglSetViewHint(app.mainView.view, PUGL_VIEW_TYPE, PUGL_VIEW_TYPE_NORMAL);
+ puglSetWindowTitle(app.mainView.view, "Main Window");
+
+ PuglStatus st = PUGL_SUCCESS;
+ if ((st = puglRealize(app.mainView.view))) {
+ return logError("Failed to realize view (%s)\n", puglStrerror(st));
+ }
+
+ puglShow(app.mainView.view);
+
+ while (!app.quit) {
+ puglUpdate(app.world, -1.0);
+ }
+
+ puglFreeView(app.mainView.view);
+ puglFreeWorld(app.world);
+ return 0;
+}
diff --git a/examples/pugl_vulkan_cpp_demo.cpp b/examples/pugl_vulkan_cpp_demo.cpp
index df0827e..487fab2 100644
--- a/examples/pugl_vulkan_cpp_demo.cpp
+++ b/examples/pugl_vulkan_cpp_demo.cpp
@@ -1475,6 +1475,7 @@ View::onEvent(const pugl::ConfigureEvent& event)
_app.extent = {static_cast<uint32_t>(event.width),
static_cast<uint32_t>(event.height)};
+ _app.resizing = event.style & PUGL_VIEW_STYLE_RESIZING;
return pugl::Status::success;
}
@@ -1640,7 +1641,6 @@ View::onEvent(const pugl::ExposeEvent&)
pugl::Status
View::onEvent(const pugl::LoopEnterEvent&)
{
- _app.resizing = true;
startTimer(resizeTimerId,
1.0 / static_cast<double>(getHint(pugl::ViewHint::refreshRate)));
@@ -1660,7 +1660,6 @@ View::onEvent(const pugl::LoopLeaveEvent&)
// Trigger a swapchain recreation with the normal present mode
_app.renderer.swapchain.extent = {};
- _app.resizing = false;
return pugl::Status::success;
}