1 /*
2 Copyright 2012-2014 David Robillard <http://drobilla.net>
3
4 Permission to use, copy, modify, and/or distribute this software for any
5 purpose with or without fee is hereby granted, provided that the above
6 copyright notice and this permission notice appear in all copies.
7
8 THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 /**
18 @file pugl_cairo_test.c A simple Pugl test that creates a top-level window.
19 */
20
21 #include <stdint.h>
22 #include <stdio.h>
23 #include <string.h>
24
25 #include <cairo/cairo.h>
26
27 #include "pugl/pugl.h"
28
29 static int quit = 0;
30 static bool entered = false;
31
32 typedef struct {
33 int x;
34 int y;
35 int w;
36 int h;
37 bool pressed;
38 const char* label;
39 } Button;
40
41 static Button toggle_button = { 16, 16, 128, 64, false, "Test" };
42
43 static void
roundedBox(cairo_t * cr,double x,double y,double w,double h)44 roundedBox(cairo_t* cr, double x, double y, double w, double h)
45 {
46 static const double radius = 10;
47 static const double degrees = 3.14159265 / 180.0;
48
49 cairo_new_sub_path(cr);
50 cairo_arc(cr,
51 x + w - radius,
52 y + radius,
53 radius, -90 * degrees, 0 * degrees);
54 cairo_arc(cr,
55 x + w - radius, y + h - radius,
56 radius, 0 * degrees, 90 * degrees);
57 cairo_arc(cr,
58 x + radius, y + h - radius,
59 radius, 90 * degrees, 180 * degrees);
60 cairo_arc(cr,
61 x + radius, y + radius,
62 radius, 180 * degrees, 270 * degrees);
63 cairo_close_path(cr);
64 }
65
66 static void
buttonDraw(cairo_t * cr,const Button * but)67 buttonDraw(cairo_t* cr, const Button* but)
68 {
69 // Draw base
70 if (but->pressed) {
71 cairo_set_source_rgba(cr, 0.4, 0.9, 0.1, 1);
72 } else {
73 cairo_set_source_rgba(cr, 0.3, 0.5, 0.1, 1);
74 }
75 roundedBox(cr, but->x, but->y, but->w, but->h);
76 cairo_fill_preserve(cr);
77
78 // Draw border
79 cairo_set_source_rgba(cr, 0.4, 0.9, 0.1, 1);
80 cairo_set_line_width(cr, 4.0);
81 cairo_stroke(cr);
82
83 // Draw label
84 cairo_text_extents_t extents;
85 cairo_set_font_size(cr, 32.0);
86 cairo_text_extents(cr, but->label, &extents);
87 cairo_move_to(cr,
88 (but->x + but->w / 2) - extents.width / 2,
89 (but->y + but->h / 2) + extents.height / 2);
90 cairo_set_source_rgba(cr, 0, 0, 0, 1);
91 cairo_show_text(cr, but->label);
92 }
93
94 static bool
buttonTouches(const Button * but,double x,double y)95 buttonTouches(const Button* but, double x, double y)
96 {
97 return (x >= toggle_button.x && x <= toggle_button.x + toggle_button.w &&
98 y >= toggle_button.y && y <= toggle_button.y + toggle_button.h);
99 }
100
101 static void
onDisplay(PuglView * view)102 onDisplay(PuglView* view)
103 {
104 cairo_t* cr = puglGetContext(view);
105
106 // Draw background
107 int width, height;
108 puglGetSize(view, &width, &height);
109 if (entered) {
110 cairo_set_source_rgb(cr, 0.1, 0.1, 0.1);
111 } else {
112 cairo_set_source_rgb(cr, 0, 0, 0);
113 }
114 cairo_rectangle(cr, 0, 0, width, height);
115 cairo_fill(cr);
116
117 // Draw button
118 buttonDraw(cr, &toggle_button);
119 }
120
121 static void
onClose(PuglView * view)122 onClose(PuglView* view)
123 {
124 quit = 1;
125 }
126
127 static void
onEvent(PuglView * view,const PuglEvent * event)128 onEvent(PuglView* view, const PuglEvent* event)
129 {
130 switch (event->type) {
131 case PUGL_KEY_PRESS:
132 if (event->key.character == 'q' ||
133 event->key.character == 'Q' ||
134 event->key.character == PUGL_CHAR_ESCAPE) {
135 quit = 1;
136 }
137 break;
138 case PUGL_BUTTON_PRESS:
139 if (buttonTouches(&toggle_button, event->button.x, event->button.y)) {
140 toggle_button.pressed = !toggle_button.pressed;
141 puglPostRedisplay(view);
142 }
143 break;
144 case PUGL_ENTER_NOTIFY:
145 entered = true;
146 puglPostRedisplay(view);
147 break;
148 case PUGL_LEAVE_NOTIFY:
149 entered = false;
150 puglPostRedisplay(view);
151 break;
152 case PUGL_EXPOSE:
153 onDisplay(view);
154 break;
155 case PUGL_CLOSE:
156 onClose(view);
157 break;
158 default: break;
159 }
160 }
161
162 int
main(int argc,char ** argv)163 main(int argc, char** argv)
164 {
165 bool useGL = false;
166 bool ignoreKeyRepeat = false;
167 bool resizable = false;
168 for (int i = 1; i < argc; ++i) {
169 if (!strcmp(argv[i], "-h")) {
170 printf("USAGE: %s [OPTIONS]...\n\n"
171 " -g Use OpenGL\n"
172 " -h Display this help\n"
173 " -i Ignore key repeat\n"
174 " -r Resizable window\n", argv[0]);
175 return 0;
176 } else if (!strcmp(argv[i], "-g")) {
177 useGL = true;
178 } else if (!strcmp(argv[i], "-i")) {
179 ignoreKeyRepeat = true;
180 } else if (!strcmp(argv[i], "-r")) {
181 resizable = true;
182 } else {
183 fprintf(stderr, "Unknown option: %s\n", argv[i]);
184 }
185 }
186
187 PuglView* view = puglInit(NULL, NULL);
188 puglInitWindowSize(view, 512, 512);
189 puglInitResizable(view, resizable);
190 puglInitContextType(view, useGL ? PUGL_CAIRO_GL : PUGL_CAIRO);
191
192 puglIgnoreKeyRepeat(view, ignoreKeyRepeat);
193 puglSetEventFunc(view, onEvent);
194
195 puglCreateWindow(view, "Pugl Test");
196 puglShowWindow(view);
197
198 while (!quit) {
199 puglWaitForEvent(view);
200 puglProcessEvents(view);
201 }
202
203 puglDestroy(view);
204 return 0;
205 }
206