aboutsummaryrefslogtreecommitdiffstats
path: root/examples/pugl_clipboard_demo.c
diff options
context:
space:
mode:
Diffstat (limited to 'examples/pugl_clipboard_demo.c')
-rw-r--r--examples/pugl_clipboard_demo.c210
1 files changed, 210 insertions, 0 deletions
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;
+}