diff options
Diffstat (limited to 'examples/pugl_cairo_demo.c')
-rw-r--r-- | examples/pugl_cairo_demo.c | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/examples/pugl_cairo_demo.c b/examples/pugl_cairo_demo.c new file mode 100644 index 0000000..94ac26e --- /dev/null +++ b/examples/pugl_cairo_demo.c @@ -0,0 +1,255 @@ +/* + Copyright 2012-2019 David Robillard <http://drobilla.net> + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +/** + @file pugl_cairo_demo.c An example of drawing with Cairo. +*/ + +#include "demo_utils.h" +#include "test/test_utils.h" + +#include "pugl/pugl.h" +#include "pugl/pugl_cairo.h" + +#include <cairo.h> + +#include <math.h> +#include <stdbool.h> +#include <stdio.h> + +static PuglWorld* world = NULL; +static PuglTestOptions opts = {0}; + +static int quit = 0; +static bool entered = false; +static bool mouseDown = false; +static unsigned framesDrawn = 0; + +typedef struct { + int x; + int y; + int w; + int h; + const char* label; +} Button; + +static Button buttons[] = { { 128, 128, 64, 64, "1" }, + { 384, 128, 64, 64, "2" }, + { 128, 384, 64, 64, "3" }, + { 384, 384, 64, 64, "4" }, + { 0, 0, 0, 0, NULL } }; + +static void +roundedBox(cairo_t* cr, double x, double y, double w, double h) +{ + static const double radius = 10; + static const double degrees = 3.14159265 / 180.0; + + cairo_new_sub_path(cr); + cairo_arc(cr, + x + w - radius, + y + radius, + radius, -90 * degrees, 0 * degrees); + cairo_arc(cr, + x + w - radius, y + h - radius, + radius, 0 * degrees, 90 * degrees); + cairo_arc(cr, + x + radius, y + h - radius, + radius, 90 * degrees, 180 * degrees); + cairo_arc(cr, + x + radius, y + radius, + radius, 180 * degrees, 270 * degrees); + cairo_close_path(cr); +} + +static void +buttonDraw(cairo_t* cr, const Button* but, const double time) +{ + cairo_save(cr); + cairo_translate(cr, but->x, but->y); + cairo_rotate(cr, sin(time) * 3.141592); + + // Draw base + if (mouseDown) { + cairo_set_source_rgba(cr, 0.4, 0.9, 0.1, 1); + } else { + cairo_set_source_rgba(cr, 0.3, 0.5, 0.1, 1); + } + roundedBox(cr, 0, 0, but->w, but->h); + cairo_fill_preserve(cr); + + // Draw border + cairo_set_source_rgba(cr, 0.4, 0.9, 0.1, 1); + cairo_set_line_width(cr, 4.0); + cairo_stroke(cr); + + // Draw label + cairo_text_extents_t extents; + cairo_set_font_size(cr, 32.0); + cairo_text_extents(cr, but->label, &extents); + cairo_move_to(cr, + (but->w / 2.0) - extents.width / 2, + (but->h / 2.0) + extents.height / 2); + cairo_set_source_rgba(cr, 0, 0, 0, 1); + cairo_show_text(cr, but->label); + + cairo_restore(cr); +} + +static void +postButtonRedisplay(PuglView* view) +{ + const PuglRect frame = puglGetFrame(view); + const double width = frame.width; + const double height = frame.height; + const double scaleX = (width - (512 / width)) / 512.0; + const double scaleY = (height - (512 / height)) / 512.0; + + for (Button* b = buttons; b->label; ++b) { + const double span = sqrt(b->w * b->w + b->h * b->h); + const PuglRect rect = {(b->x - span) * scaleX, + (b->y - span) * scaleY, + span * 2.0 * scaleX, + span * 2.0 * scaleY}; + + puglPostRedisplayRect(view, rect); + } +} + +static void +onDisplay(PuglView* view, const PuglEventExpose* event) +{ + cairo_t* cr = (cairo_t*)puglGetContext(view); + + cairo_rectangle(cr, event->x, event->y, event->width, event->height); + cairo_clip_preserve(cr); + + // Draw background + const PuglRect frame = puglGetFrame(view); + const double width = frame.width; + const double height = frame.height; + if (entered) { + cairo_set_source_rgb(cr, 0.1, 0.1, 0.1); + } else { + cairo_set_source_rgb(cr, 0, 0, 0); + } + cairo_fill(cr); + + // Scale to view size + const double scaleX = (width - (512 / width)) / 512.0; + const double scaleY = (height - (512 / height)) / 512.0; + cairo_scale(cr, scaleX, scaleY); + + // Draw button + for (Button* b = buttons; b->label; ++b) { + buttonDraw(cr, b, opts.continuous ? puglGetTime(world) : 0.0); + } + + ++framesDrawn; +} + +static void +onClose(PuglView* view) +{ + (void)view; + quit = 1; +} + +static PuglStatus +onEvent(PuglView* view, const PuglEvent* event) +{ + switch (event->type) { + case PUGL_KEY_PRESS: + if (event->key.key == 'q' || event->key.key == PUGL_KEY_ESCAPE) { + quit = 1; + } + break; + case PUGL_BUTTON_PRESS: + mouseDown = true; + postButtonRedisplay(view); + break; + case PUGL_BUTTON_RELEASE: + mouseDown = false; + postButtonRedisplay(view); + break; + case PUGL_ENTER_NOTIFY: + entered = true; + puglPostRedisplay(view); + break; + case PUGL_LEAVE_NOTIFY: + entered = false; + puglPostRedisplay(view); + break; + case PUGL_EXPOSE: + onDisplay(view, &event->expose); + break; + case PUGL_CLOSE: + onClose(view); + break; + default: break; + } + + return PUGL_SUCCESS; +} + +int +main(int argc, char** argv) +{ + opts = puglParseTestOptions(&argc, &argv); + if (opts.help) { + puglPrintTestUsage("pugl_test", ""); + return 1; + } + + world = puglNewWorld(); + puglSetClassName(world, "PuglCairoTest"); + + PuglRect frame = { 0, 0, 512, 512 }; + PuglView* view = puglNewView(world); + puglSetFrame(view, frame); + puglSetMinSize(view, 256, 256); + puglSetViewHint(view, PUGL_RESIZABLE, opts.resizable); + puglSetBackend(view, puglCairoBackend()); + + puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, opts.ignoreKeyRepeat); + puglSetEventFunc(view, onEvent); + + PuglStatus st = puglCreateWindow(view, "Pugl Test"); + if (st) { + return logError("Failed to create window (%s)\n", puglStrerror(st)); + } + + puglShowWindow(view); + + PuglFpsPrinter fpsPrinter = { puglGetTime(world) }; + while (!quit) { + if (opts.continuous) { + postButtonRedisplay(view); + } else { + puglPollEvents(world, -1); + } + + puglDispatchEvents(world); + + if (opts.continuous) { + puglPrintFps(world, &fpsPrinter, &framesDrawn); + } + } + + puglFreeView(view); + puglFreeWorld(world); + return 0; +} |