aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2021-05-06 17:14:58 -0400
committerDavid Robillard <d@drobilla.net>2022-05-22 20:16:26 -0400
commit7c9d6d5d16fc0c72a27f0118ac753980e518ebcd (patch)
treedc977252a7d93a4ca5fe840b978568178708e873
parentfdd6de0d12ea17f713ec3e73e7968198339b7b6d (diff)
downloadpugl-7c9d6d5d16fc0c72a27f0118ac753980e518ebcd.tar.gz
pugl-7c9d6d5d16fc0c72a27f0118ac753980e518ebcd.tar.bz2
pugl-7c9d6d5d16fc0c72a27f0118ac753980e518ebcd.zip
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.
-rw-r--r--examples/meson.build2
-rw-r--r--examples/pugl_clipboard_demo.app/MacOS/meson.build9
-rw-r--r--examples/pugl_clipboard_demo.app/meson.build11
-rw-r--r--examples/pugl_clipboard_demo.c210
-rw-r--r--examples/pugl_embed_demo.c18
5 files changed, 236 insertions, 14 deletions
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 <d@drobilla.net>
+# 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 <d@drobilla.net>
+# 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 <d@drobilla.net>
+// 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 <math.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+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 <d@drobilla.net>
+// Copyright 2012-2022 David Robillard <d@drobilla.net>
// SPDX-License-Identifier: ISC
#include "cube_view.h"
@@ -11,8 +11,6 @@
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
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;