From 7c9d6d5d16fc0c72a27f0118ac753980e518ebcd Mon Sep 17 00:00:00 2001 From: David Robillard Date: Thu, 6 May 2021 17:14:58 -0400 Subject: Factor out pugl_clipboard_demo example program This is a simpler example than pugl_embed_demo that demonstrates clipboard functionality without the complexity of embedded views. --- examples/meson.build | 2 + examples/pugl_clipboard_demo.app/MacOS/meson.build | 9 + examples/pugl_clipboard_demo.app/meson.build | 11 ++ examples/pugl_clipboard_demo.c | 210 +++++++++++++++++++++ examples/pugl_embed_demo.c | 18 +- 5 files changed, 236 insertions(+), 14 deletions(-) create mode 100644 examples/pugl_clipboard_demo.app/MacOS/meson.build create mode 100644 examples/pugl_clipboard_demo.app/meson.build create mode 100644 examples/pugl_clipboard_demo.c diff --git a/examples/meson.build b/examples/meson.build index 0308d2c..a981cdd 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -9,6 +9,7 @@ stub_examples = [ ] gl_examples = [ + 'pugl_clipboard_demo.c', 'pugl_cpp_demo.cpp', 'pugl_cursor_demo.c', 'pugl_embed_demo.c', @@ -81,6 +82,7 @@ subdir('shaders') if host_machine.system() == 'darwin' # On Darwin, build examples as application bundles (required to work properly) + subdir('pugl_clipboard_demo.app') if cairo_dep.found() subdir('pugl_cairo_demo.app') diff --git a/examples/pugl_clipboard_demo.app/MacOS/meson.build b/examples/pugl_clipboard_demo.app/MacOS/meson.build new file mode 100644 index 0000000..1fcb023 --- /dev/null +++ b/examples/pugl_clipboard_demo.app/MacOS/meson.build @@ -0,0 +1,9 @@ +# Copyright 2021 David Robillard +# SPDX-License-Identifier: CC0-1.0 OR ISC + +executable( + 'pugl_clipboard_demo', + '../../pugl_clipboard_demo.c', + include_directories: include_directories('../../../../include', '../../..'), + c_args: example_defines + example_c_args, + dependencies: [pugl_dep, gl_backend_dep]) diff --git a/examples/pugl_clipboard_demo.app/meson.build b/examples/pugl_clipboard_demo.app/meson.build new file mode 100644 index 0000000..fff35b9 --- /dev/null +++ b/examples/pugl_clipboard_demo.app/meson.build @@ -0,0 +1,11 @@ +# Copyright 2021 David Robillard +# SPDX-License-Identifier: CC0-1.0 OR ISC + +config = configuration_data() +config.set('NAME', 'pugl_clipboard_demo') + +info_plist = configure_file(configuration: config, + input: files('../../resources/Info.plist.in'), + output: 'Info.plist') + +subdir('MacOS') diff --git a/examples/pugl_clipboard_demo.c b/examples/pugl_clipboard_demo.c new file mode 100644 index 0000000..76e42f8 --- /dev/null +++ b/examples/pugl_clipboard_demo.c @@ -0,0 +1,210 @@ +// Copyright 2012-2022 David Robillard +// SPDX-License-Identifier: ISC + +// A demonstration of using clipboards for copy/paste and drag and drop + +#include "cube_view.h" +#include "test/test_utils.h" + +#include "pugl/gl.h" +#include "pugl/pugl.h" + +#include +#include +#include +#include + +typedef struct { + PuglView* view; + double xAngle; + double yAngle; + double lastMouseX; + double lastMouseY; + double lastDrawTime; + bool entered; +} CubeView; + +typedef struct { + PuglWorld* world; + CubeView cube; + int quit; + bool continuous; + bool verbose; +} PuglTestApp; + +static void +onDisplay(PuglView* view) +{ + PuglWorld* world = puglGetWorld(view); + PuglTestApp* app = (PuglTestApp*)puglGetWorldHandle(world); + CubeView* cube = (CubeView*)puglGetHandle(view); + + const double thisTime = puglGetTime(app->world); + if (app->continuous) { + const double dTime = thisTime - cube->lastDrawTime; + + cube->xAngle = fmod(cube->xAngle + dTime * 100.0, 360.0); + cube->yAngle = fmod(cube->yAngle + dTime * 100.0, 360.0); + } + + displayCube( + view, 10.0f, (float)cube->xAngle, (float)cube->yAngle, cube->entered); + + cube->lastDrawTime = thisTime; +} + +static void +onKeyPress(PuglView* const view, const PuglKeyEvent* const event) +{ + static const char* const copyString = "Pugl test"; + + PuglWorld* const world = puglGetWorld(view); + PuglTestApp* const app = (PuglTestApp*)puglGetWorldHandle(world); + + if (event->key == 'q' || event->key == PUGL_KEY_ESCAPE) { + app->quit = 1; + } else if ((event->state & PUGL_MOD_CTRL) && event->key == 'c') { + puglSetClipboard(view, NULL, copyString, strlen(copyString) + 1); + + fprintf(stderr, "Copy \"%s\"\n", copyString); + } else if ((event->state & PUGL_MOD_CTRL) && event->key == 'v') { + const char* type = NULL; + size_t len = 0; + const char* text = (const char*)puglGetClipboard(view, &type, &len); + + fprintf(stderr, "Paste \"%s\"\n", text); + } +} + +static void +redisplayView(PuglTestApp* app, PuglView* view) +{ + if (!app->continuous) { + puglPostRedisplay(view); + } +} + +static PuglStatus +onEvent(PuglView* view, const PuglEvent* event) +{ + PuglWorld* world = puglGetWorld(view); + PuglTestApp* app = (PuglTestApp*)puglGetWorldHandle(world); + CubeView* cube = (CubeView*)puglGetHandle(view); + + printEvent(event, "Event: ", app->verbose); + + switch (event->type) { + case PUGL_CONFIGURE: + reshapeCube((float)event->configure.width, (float)event->configure.height); + break; + case PUGL_UPDATE: + if (app->continuous) { + puglPostRedisplay(view); + } + break; + case PUGL_EXPOSE: + onDisplay(view); + break; + case PUGL_CLOSE: + app->quit = 1; + break; + case PUGL_KEY_PRESS: + onKeyPress(view, &event->key); + break; + case PUGL_MOTION: +#if defined(__GNUC__) && (__GNUC__ >= 5) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wfloat-conversion" +#endif + if (isnan(cube->lastMouseX)) { + cube->lastMouseX = event->motion.x; + } + if (isnan(cube->lastMouseY)) { + cube->lastMouseY = event->motion.y; + } +#if defined(__GNUC__) && (__GNUC__ >= 5) +# pragma GCC diagnostic pop +#endif + cube->xAngle -= (event->motion.x - cube->lastMouseX) / 2.0; + cube->yAngle += (event->motion.y - cube->lastMouseY) / 2.0; + cube->lastMouseX = event->motion.x; + cube->lastMouseY = event->motion.y; + redisplayView(app, view); + break; + case PUGL_POINTER_IN: + cube->entered = true; + redisplayView(app, view); + break; + case PUGL_POINTER_OUT: + cube->entered = false; + redisplayView(app, view); + break; + case PUGL_FOCUS_IN: + case PUGL_FOCUS_OUT: + redisplayView(app, view); + break; + default: + break; + } + + return PUGL_SUCCESS; +} + +int +main(int argc, char** argv) +{ + // Parse command line options + const PuglTestOptions opts = puglParseTestOptions(&argc, &argv); + if (opts.help) { + puglPrintTestUsage(argv[0], ""); + return 1; + } + + PuglTestApp app = {0}; + + app.world = puglNewWorld(PUGL_PROGRAM, 0); + app.cube.view = puglNewView(app.world); + app.cube.xAngle = 30.0; + app.cube.yAngle = -30.0; + app.cube.lastMouseX = (double)NAN; + app.cube.lastMouseY = (double)NAN; + app.verbose = opts.verbose; + app.continuous = opts.continuous; + + PuglStatus st = PUGL_SUCCESS; + PuglView* const view = app.cube.view; + + puglSetWorldHandle(app.world, &app); + puglSetClassName(app.world, "Pugl Test"); + + puglSetWindowTitle(view, "Pugl Clipboard Demo"); + puglSetSizeHint(view, PUGL_DEFAULT_SIZE, 512, 512); + puglSetSizeHint(view, PUGL_MIN_SIZE, 128, 128); + puglSetBackend(view, puglGlBackend()); + + puglSetViewHint(view, PUGL_USE_DEBUG_CONTEXT, opts.errorChecking); + puglSetViewHint(view, PUGL_RESIZABLE, opts.resizable); + puglSetViewHint(view, PUGL_SAMPLES, opts.samples); + puglSetViewHint(view, PUGL_DOUBLE_BUFFER, opts.doubleBuffer); + puglSetViewHint(view, PUGL_SWAP_INTERVAL, opts.sync); + puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, opts.ignoreKeyRepeat); + puglSetHandle(view, &app.cube); + puglSetEventFunc(view, onEvent); + + if ((st = puglRealize(view))) { + return logError("Failed to realize view (%s)\n", puglStrerror(st)); + } + + if ((st = puglShow(view))) { + return logError("Failed to show view (%s)\n", puglStrerror(st)); + } + + while (!app.quit) { + puglUpdate(app.world, app.continuous ? 0.0 : -1.0); + } + + puglFreeView(app.cube.view); + puglFreeWorld(app.world); + + return 0; +} diff --git a/examples/pugl_embed_demo.c b/examples/pugl_embed_demo.c index af48a15..f7e4676 100644 --- a/examples/pugl_embed_demo.c +++ b/examples/pugl_embed_demo.c @@ -1,4 +1,4 @@ -// Copyright 2012-2020 David Robillard +// Copyright 2012-2022 David Robillard // SPDX-License-Identifier: ISC #include "cube_view.h" @@ -11,8 +11,6 @@ #include #include #include -#include -#include static const uint8_t borderWidth = 64u; static const uintptr_t reverseTimerId = 1u; @@ -100,7 +98,7 @@ swapFocus(PuglTestApp* app) } static void -onKeyPress(PuglView* view, const PuglKeyEvent* event, const char* prefix) +onKeyPress(PuglView* view, const PuglKeyEvent* event) { PuglTestApp* app = (PuglTestApp*)puglGetHandle(view); PuglRect frame = puglGetFrame(view); @@ -109,14 +107,6 @@ onKeyPress(PuglView* view, const PuglKeyEvent* event, const char* prefix) swapFocus(app); } else if (event->key == 'q' || event->key == PUGL_KEY_ESCAPE) { app->quit = 1; - } else if (event->state & PUGL_MOD_CTRL && event->key == 'c') { - puglSetClipboard(view, NULL, "Pugl test", strlen("Pugl test") + 1); - fprintf(stderr, "%sCopy \"Pugl test\"\n", prefix); - } else if (event->state & PUGL_MOD_CTRL && event->key == 'v') { - const char* type = NULL; - size_t len = 0; - const char* text = (const char*)puglGetClipboard(view, &type, &len); - fprintf(stderr, "%sPaste \"%s\"\n", prefix, text); } else if (event->state & PUGL_MOD_SHIFT) { if (event->key == PUGL_KEY_UP) { puglSetSize(view, frame.width, frame.height - 10u); @@ -178,7 +168,7 @@ onParentEvent(PuglView* view, const PuglEvent* event) } break; case PUGL_KEY_PRESS: - onKeyPress(view, &event->key, "Parent: "); + onKeyPress(view, &event->key); break; case PUGL_MOTION: break; @@ -215,7 +205,7 @@ onEvent(PuglView* view, const PuglEvent* event) app->quit = 1; break; case PUGL_KEY_PRESS: - onKeyPress(view, &event->key, "Child: "); + onKeyPress(view, &event->key); break; case PUGL_MOTION: app->xAngle -= event->motion.x - app->lastMouseX; -- cgit v1.2.1