1 /*
2 Copyright 2012-2020 David Robillard <d@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 #ifndef PUGL_PUGL_HPP
18 #define PUGL_PUGL_HPP
19
20 #include "pugl/pugl.h"
21
22 #include <cstdint>
23
24 #if defined(PUGL_HPP_THROW_FAILED_CONSTRUCTION)
25 # include <exception>
26 #elif defined(PUGL_HPP_ASSERT_CONSTRUCTION)
27 # include <cassert>
28 #endif
29
30 namespace pugl {
31
32 /**
33 @defgroup puglxx Pugl C++ API
34 Pugl C++ API wrapper.
35 @{
36 */
37
38 namespace detail {
39
40 /// Free function for a C object
41 template<typename T>
42 using FreeFunc = void (*)(T*);
43
44 /// Generic C++ wrapper for a C object
45 template<class T, FreeFunc<T> Free>
46 class Wrapper
47 {
48 public:
49 Wrapper(const Wrapper&) = delete;
50 Wrapper& operator=(const Wrapper&) = delete;
51
Wrapper(Wrapper && wrapper)52 Wrapper(Wrapper&& wrapper) noexcept
53 : _ptr{wrapper._ptr}
54 {
55 wrapper._ptr = nullptr;
56 }
57
operator =(Wrapper && wrapper)58 Wrapper& operator=(Wrapper&& wrapper) noexcept
59 {
60 _ptr = wrapper._ptr;
61 wrapper._ptr = nullptr;
62 return *this;
63 }
64
~Wrapper()65 ~Wrapper() noexcept { Free(_ptr); }
66
cobj()67 T* cobj() noexcept { return _ptr; }
cobj() const68 const T* cobj() const noexcept { return _ptr; }
69
70 protected:
Wrapper(T * ptr)71 explicit Wrapper(T* ptr) noexcept
72 : _ptr{ptr}
73 {}
74
75 private:
76 T* _ptr;
77 };
78
79 } // namespace detail
80
81 using Rect = PuglRect; ///< @copydoc PuglRect
82
83 /**
84 @defgroup eventsxx Events
85 @{
86 */
87
88 /**
89 A strongly-typed analogue of PuglEvent.
90
91 This is bit-for-bit identical to the corresponding PuglEvent, so events are
92 simply cast to this type to avoid any copying overhead.
93
94 @tparam t The `type` field of the corresponding PuglEvent.
95
96 @tparam Base The specific struct type of the corresponding PuglEvent.
97 */
98 template<PuglEventType t, class Base>
99 struct Event final : Base {
100 /// The type of the corresponding C event structure
101 using BaseEvent = Base;
102
103 /// The `type` field of the corresponding C event structure
104 static constexpr const PuglEventType type = t;
105 };
106
107 using Mod = PuglMod; ///< @copydoc PuglMod
108 using Mods = PuglMods; ///< @copydoc PuglMods
109 using Key = PuglKey; ///< @copydoc PuglKey
110 using EventType = PuglEventType; ///< @copydoc PuglEventType
111 using EventFlag = PuglEventFlag; ///< @copydoc PuglEventFlag
112 using EventFlags = PuglEventFlags; ///< @copydoc PuglEventFlags
113 using CrossingMode = PuglCrossingMode; ///< @copydoc PuglCrossingMode
114
115 /// @copydoc PuglEventCreate
116 using CreateEvent = Event<PUGL_CREATE, PuglEventCreate>;
117
118 /// @copydoc PuglEventDestroy
119 using DestroyEvent = Event<PUGL_DESTROY, PuglEventDestroy>;
120
121 /// @copydoc PuglEventConfigure
122 using ConfigureEvent = Event<PUGL_CONFIGURE, PuglEventConfigure>;
123
124 /// @copydoc PuglEventMap
125 using MapEvent = Event<PUGL_MAP, PuglEventMap>;
126
127 /// @copydoc PuglEventUnmap
128 using UnmapEvent = Event<PUGL_UNMAP, PuglEventUnmap>;
129
130 /// @copydoc PuglEventUpdate
131 using UpdateEvent = Event<PUGL_UPDATE, PuglEventUpdate>;
132
133 /// @copydoc PuglEventExpose
134 using ExposeEvent = Event<PUGL_EXPOSE, PuglEventExpose>;
135
136 /// @copydoc PuglEventClose
137 using CloseEvent = Event<PUGL_CLOSE, PuglEventClose>;
138
139 /// @copydoc PuglEventFocus
140 using FocusInEvent = Event<PUGL_FOCUS_IN, PuglEventFocus>;
141
142 /// @copydoc PuglEventFocus
143 using FocusOutEvent = Event<PUGL_FOCUS_OUT, PuglEventFocus>;
144
145 /// @copydoc PuglEventKey
146 using KeyPressEvent = Event<PUGL_KEY_PRESS, PuglEventKey>;
147
148 /// @copydoc PuglEventKey
149 using KeyReleaseEvent = Event<PUGL_KEY_RELEASE, PuglEventKey>;
150
151 /// @copydoc PuglEventText
152 using TextEvent = Event<PUGL_TEXT, PuglEventText>;
153
154 /// @copydoc PuglEventCrossing
155 using PointerInEvent = Event<PUGL_POINTER_IN, PuglEventCrossing>;
156
157 /// @copydoc PuglEventCrossing
158 using PointerOutEvent = Event<PUGL_POINTER_OUT, PuglEventCrossing>;
159
160 /// @copydoc PuglEventButton
161 using ButtonPressEvent = Event<PUGL_BUTTON_PRESS, PuglEventButton>;
162
163 /// @copydoc PuglEventButton
164 using ButtonReleaseEvent = Event<PUGL_BUTTON_RELEASE, PuglEventButton>;
165
166 /// @copydoc PuglEventMotion
167 using MotionEvent = Event<PUGL_MOTION, PuglEventMotion>;
168
169 /// @copydoc PuglEventScroll
170 using ScrollEvent = Event<PUGL_SCROLL, PuglEventScroll>;
171
172 /// @copydoc PuglEventClient
173 using ClientEvent = Event<PUGL_CLIENT, PuglEventClient>;
174
175 /// @copydoc PuglEventTimer
176 using TimerEvent = Event<PUGL_TIMER, PuglEventTimer>;
177
178 /// @copydoc PuglEventLoopEnter
179 using LoopEnterEvent = Event<PUGL_LOOP_ENTER, PuglEventLoopEnter>;
180
181 /// @copydoc PuglEventLoopLeave
182 using LoopLeaveEvent = Event<PUGL_LOOP_LEAVE, PuglEventLoopLeave>;
183
184 /**
185 @}
186 @defgroup statusxx Status
187 @{
188 */
189
190 /// @copydoc PuglStatus
191 enum class Status {
192 success, ///< @copydoc PUGL_SUCCESS
193 failure, ///< @copydoc PUGL_FAILURE
194 unknownError, ///< @copydoc PUGL_UNKNOWN_ERROR
195 badBackend, ///< @copydoc PUGL_BAD_BACKEND
196 badConfiguration, ///< @copydoc PUGL_BAD_CONFIGURATION
197 badParameter, ///< @copydoc PUGL_BAD_PARAMETER
198 backendFailed, ///< @copydoc PUGL_BACKEND_FAILED
199 registrationFailed, ///< @copydoc PUGL_REGISTRATION_FAILED
200 realizeFailed, ///< @copydoc PUGL_REALIZE_FAILED
201 setFormatFailed, ///< @copydoc PUGL_SET_FORMAT_FAILED
202 createContextFailed, ///< @copydoc PUGL_CREATE_CONTEXT_FAILED
203 unsupportedType, ///< @copydoc PUGL_UNSUPPORTED_TYPE
204 };
205
206 static_assert(Status(PUGL_UNSUPPORTED_TYPE) == Status::unsupportedType, "");
207
208 /// @copydoc puglStrerror
209 inline const char*
strerror(const Status status)210 strerror(const Status status) noexcept
211 {
212 return puglStrerror(static_cast<PuglStatus>(status));
213 }
214
215 /**
216 @}
217 @defgroup worldxx World
218 @{
219 */
220
221 /// @copydoc PuglWorldType
222 enum class WorldType {
223 program, ///< @copydoc PUGL_PROGRAM
224 module, ///< @copydoc PUGL_MODULE
225 };
226
227 static_assert(WorldType(PUGL_MODULE) == WorldType::module, "");
228
229 /// @copydoc PuglWorldFlag
230 enum class WorldFlag {
231 threads = PUGL_WORLD_THREADS, ///< @copydoc PUGL_WORLD_THREADS
232 };
233
234 static_assert(WorldFlag(PUGL_WORLD_THREADS) == WorldFlag::threads, "");
235
236 using WorldFlags = PuglWorldFlags; ///< @copydoc PuglWorldFlags
237
238 #if defined(PUGL_HPP_THROW_FAILED_CONSTRUCTION)
239
240 /// An exception thrown when construction fails
241 class FailedConstructionError : public std::exception
242 {
243 public:
FailedConstructionError(const char * const msg)244 FailedConstructionError(const char* const msg) noexcept
245 : _msg{msg}
246 {}
247
248 virtual const char* what() const noexcept override;
249
250 private:
251 const char* _msg;
252 };
253
254 # define PUGL_CHECK_CONSTRUCTION(cond, msg) \
255 do { \
256 if (!(cond)) { \
257 throw FailedConstructionError(msg); \
258 } \
259 } while (0)
260
261 #elif defined(PUGL_HPP_ASSERT_CONSTRUCTION)
262 # define PUGL_CHECK_CONSTRUCTION(cond, msg) assert(cond);
263 #else
264 /**
265 Configurable macro for handling construction failure.
266
267 If `PUGL_HPP_THROW_FAILED_CONSTRUCTION` is defined, then this throws a
268 `pugl::FailedConstructionError` if construction fails.
269
270 If `PUGL_HPP_ASSERT_CONSTRUCTION` is defined, then this asserts if
271 construction fails.
272
273 Otherwise, this does nothing.
274 */
275 # define PUGL_CHECK_CONSTRUCTION(cond, msg)
276 #endif
277
278 /// @copydoc PuglWorld
279 class World : public detail::Wrapper<PuglWorld, puglFreeWorld>
280 {
281 public:
282 World(const World&) = delete;
283 World& operator=(const World&) = delete;
284
285 World(World&&) = delete;
286 World& operator=(World&&) = delete;
287
288 ~World() = default;
289
World(WorldType type,WorldFlag flag)290 World(WorldType type, WorldFlag flag)
291 : Wrapper{puglNewWorld(static_cast<PuglWorldType>(type),
292 static_cast<PuglWorldFlags>(flag))}
293 {
294 PUGL_CHECK_CONSTRUCTION(cobj(), "Failed to create pugl::World");
295 }
296
World(WorldType type,WorldFlags flags)297 World(WorldType type, WorldFlags flags)
298 : Wrapper{puglNewWorld(static_cast<PuglWorldType>(type), flags)}
299 {
300 PUGL_CHECK_CONSTRUCTION(cobj(), "Failed to create pugl::World");
301 }
302
World(WorldType type)303 explicit World(WorldType type)
304 : World{type, WorldFlags{}}
305 {}
306
307 /// @copydoc puglGetNativeWorld
nativeWorld()308 void* nativeWorld() noexcept { return puglGetNativeWorld(cobj()); }
309
310 /// @copydoc puglSetClassName
setClassName(const char * const name)311 Status setClassName(const char* const name) noexcept
312 {
313 return static_cast<Status>(puglSetClassName(cobj(), name));
314 }
315
316 /// @copydoc puglGetTime
time() const317 double time() const noexcept { return puglGetTime(cobj()); }
318
319 /// @copydoc puglUpdate
update(const double timeout)320 Status update(const double timeout) noexcept
321 {
322 return static_cast<Status>(puglUpdate(cobj(), timeout));
323 }
324 };
325
326 /**
327 @}
328 @defgroup viewxx View
329 @{
330 */
331
332 using Backend = PuglBackend; ///< @copydoc PuglBackend
333 using NativeView = PuglNativeView; ///< @copydoc PuglNativeView
334
335 /// @copydoc PuglViewHint
336 enum class ViewHint {
337 useCompatProfile, ///< @copydoc PUGL_USE_COMPAT_PROFILE
338 useDebugContext, ///< @copydoc PUGL_USE_DEBUG_CONTEXT
339 contextVersionMajor, ///< @copydoc PUGL_CONTEXT_VERSION_MAJOR
340 contextVersionMinor, ///< @copydoc PUGL_CONTEXT_VERSION_MINOR
341 redBits, ///< @copydoc PUGL_RED_BITS
342 greenBits, ///< @copydoc PUGL_GREEN_BITS
343 blueBits, ///< @copydoc PUGL_BLUE_BITS
344 alphaBits, ///< @copydoc PUGL_ALPHA_BITS
345 depthBits, ///< @copydoc PUGL_DEPTH_BITS
346 stencilBits, ///< @copydoc PUGL_STENCIL_BITS
347 samples, ///< @copydoc PUGL_SAMPLES
348 doubleBuffer, ///< @copydoc PUGL_DOUBLE_BUFFER
349 swapInterval, ///< @copydoc PUGL_SWAP_INTERVAL
350 resizable, ///< @copydoc PUGL_RESIZABLE
351 ignoreKeyRepeat, ///< @copydoc PUGL_IGNORE_KEY_REPEAT
352 refreshRate, ///< @copydoc PUGL_REFRESH_RATE
353 };
354
355 static_assert(ViewHint(PUGL_REFRESH_RATE) == ViewHint::refreshRate, "");
356
357 using ViewHintValue = PuglViewHintValue; ///< @copydoc PuglViewHintValue
358
359 /// @copydoc PuglCursor
360 enum class Cursor {
361 arrow, ///< @copydoc PUGL_CURSOR_ARROW
362 caret, ///< @copydoc PUGL_CURSOR_CARET
363 crosshair, ///< @copydoc PUGL_CURSOR_CROSSHAIR
364 hand, ///< @copydoc PUGL_CURSOR_HAND
365 no, ///< @copydoc PUGL_CURSOR_NO
366 leftRight, ///< @copydoc PUGL_CURSOR_LEFT_RIGHT
367 upDown, ///< @copydoc PUGL_CURSOR_UP_DOWN
368 };
369
370 static_assert(Cursor(PUGL_CURSOR_UP_DOWN) == Cursor::upDown, "");
371
372 /// @copydoc PuglView
373 class View : protected detail::Wrapper<PuglView, puglFreeView>
374 {
375 public:
376 /**
377 @name Setup
378 Methods for creating and destroying a view.
379 @{
380 */
381
View(World & world)382 explicit View(World& world)
383 : Wrapper{puglNewView(world.cobj())}
384 , _world(world)
385 {
386 PUGL_CHECK_CONSTRUCTION(cobj(), "Failed to create pugl::View");
387 }
388
world() const389 const World& world() const noexcept { return _world; }
world()390 World& world() noexcept { return _world; }
391
392 /**
393 Set the object that will be called to handle events.
394
395 This is a type-safe wrapper for the C functions puglSetHandle() and
396 puglSetEventFunc() that will automatically dispatch events to the
397 `onEvent` method of `handler` that takes the appropriate event type.
398 The handler must have such a method defined for every event type, but if
399 the handler is the view itself, a `using` declaration can be used to
400 "inherit" the default implementation to avoid having to define every
401 method. For example:
402
403 @code
404 class MyView : public pugl::View
405 {
406 public:
407 explicit MyView(pugl::World& world)
408 : pugl::View{world}
409 {
410 setEventHandler(*this);
411 }
412
413 using pugl::View::onEvent;
414
415 pugl::Status onEvent(const pugl::ConfigureEvent& event) noexcept;
416 pugl::Status onEvent(const pugl::ExposeEvent& event) noexcept;
417 };
418 @endcode
419
420 This facility is just a convenience, applications may use the C API
421 directly to set a handle and event function to set up a different
422 approach for event handling.
423 */
424 template<class Handler>
setEventHandler(Handler & handler)425 Status setEventHandler(Handler& handler)
426 {
427 puglSetHandle(cobj(), &handler);
428 return static_cast<Status>(puglSetEventFunc(cobj(), eventFunc<Handler>));
429 }
430
431 /// @copydoc puglSetBackend
setBackend(const PuglBackend * backend)432 Status setBackend(const PuglBackend* backend) noexcept
433 {
434 return static_cast<Status>(puglSetBackend(cobj(), backend));
435 }
436
437 /// @copydoc puglSetViewHint
setHint(ViewHint hint,int value)438 Status setHint(ViewHint hint, int value) noexcept
439 {
440 return static_cast<Status>(
441 puglSetViewHint(cobj(), static_cast<PuglViewHint>(hint), value));
442 }
443
444 /// @copydoc puglGetViewHint
getHint(ViewHint hint)445 int getHint(ViewHint hint) noexcept
446 {
447 return puglGetViewHint(cobj(), static_cast<PuglViewHint>(hint));
448 }
449
450 /**
451 @}
452 @name Frame
453 Methods for working with the position and size of a view.
454 @{
455 */
456
457 /// @copydoc puglGetFrame
frame() const458 Rect frame() const noexcept { return puglGetFrame(cobj()); }
459
460 /// @copydoc puglSetFrame
setFrame(Rect frame)461 Status setFrame(Rect frame) noexcept
462 {
463 return static_cast<Status>(puglSetFrame(cobj(), frame));
464 }
465
466 /// @copydoc puglSetDefaultSize
setDefaultSize(int width,int height)467 Status setDefaultSize(int width, int height) noexcept
468 {
469 return static_cast<Status>(puglSetDefaultSize(cobj(), width, height));
470 }
471
472 /// @copydoc puglSetMinSize
setMinSize(int width,int height)473 Status setMinSize(int width, int height) noexcept
474 {
475 return static_cast<Status>(puglSetMinSize(cobj(), width, height));
476 }
477
478 /// @copydoc puglSetMaxSize
setMaxSize(int width,int height)479 Status setMaxSize(int width, int height) noexcept
480 {
481 return static_cast<Status>(puglSetMaxSize(cobj(), width, height));
482 }
483
484 /// @copydoc puglSetAspectRatio
setAspectRatio(int minX,int minY,int maxX,int maxY)485 Status setAspectRatio(int minX, int minY, int maxX, int maxY) noexcept
486 {
487 return static_cast<Status>(
488 puglSetAspectRatio(cobj(), minX, minY, maxX, maxY));
489 }
490
491 /**
492 @}
493 @name Windows
494 Methods for working with top-level windows.
495 @{
496 */
497
498 /// @copydoc puglSetWindowTitle
setWindowTitle(const char * title)499 Status setWindowTitle(const char* title) noexcept
500 {
501 return static_cast<Status>(puglSetWindowTitle(cobj(), title));
502 }
503
504 /// @copydoc puglSetParentWindow
setParentWindow(NativeView parent)505 Status setParentWindow(NativeView parent) noexcept
506 {
507 return static_cast<Status>(puglSetParentWindow(cobj(), parent));
508 }
509
510 /// @copydoc puglSetTransientFor
setTransientFor(NativeView parent)511 Status setTransientFor(NativeView parent) noexcept
512 {
513 return static_cast<Status>(puglSetTransientFor(cobj(), parent));
514 }
515
516 /// @copydoc puglRealize
realize()517 Status realize() noexcept { return static_cast<Status>(puglRealize(cobj())); }
518
519 /// @copydoc puglShow
show()520 Status show() noexcept { return static_cast<Status>(puglShow(cobj())); }
521
522 /// @copydoc puglHide
hide()523 Status hide() noexcept { return static_cast<Status>(puglHide(cobj())); }
524
525 /// @copydoc puglGetVisible
visible() const526 bool visible() const noexcept { return puglGetVisible(cobj()); }
527
528 /// @copydoc puglGetNativeWindow
nativeWindow()529 NativeView nativeWindow() noexcept { return puglGetNativeWindow(cobj()); }
530
531 /**
532 @}
533 @name Graphics
534 Methods for working with the graphics context and scheduling
535 redisplays.
536 @{
537 */
538
539 /// @copydoc puglGetContext
context()540 void* context() noexcept { return puglGetContext(cobj()); }
541
542 /// @copydoc puglPostRedisplay
postRedisplay()543 Status postRedisplay() noexcept
544 {
545 return static_cast<Status>(puglPostRedisplay(cobj()));
546 }
547
548 /// @copydoc puglPostRedisplayRect
postRedisplayRect(const Rect rect)549 Status postRedisplayRect(const Rect rect) noexcept
550 {
551 return static_cast<Status>(puglPostRedisplayRect(cobj(), rect));
552 }
553
554 /**
555 @}
556 @name Interaction
557 Methods for interacting with the user and window system.
558 @{
559 */
560
561 /// @copydoc puglGrabFocus
grabFocus()562 Status grabFocus() noexcept
563 {
564 return static_cast<Status>(puglGrabFocus(cobj()));
565 }
566
567 /// @copydoc puglHasFocus
hasFocus() const568 bool hasFocus() const noexcept { return puglHasFocus(cobj()); }
569
570 /// @copydoc puglSetCursor
setCursor(const Cursor cursor)571 Status setCursor(const Cursor cursor) noexcept
572 {
573 return static_cast<Status>(
574 puglSetCursor(cobj(), static_cast<PuglCursor>(cursor)));
575 }
576
577 /// @copydoc puglRequestAttention
requestAttention()578 Status requestAttention() noexcept
579 {
580 return static_cast<Status>(puglRequestAttention(cobj()));
581 }
582
583 /// @copydoc puglStartTimer
startTimer(const uintptr_t id,const double timeout)584 Status startTimer(const uintptr_t id, const double timeout) noexcept
585 {
586 return static_cast<Status>(puglStartTimer(cobj(), id, timeout));
587 }
588
589 /// @copydoc puglStopTimer
stopTimer(const uintptr_t id)590 Status stopTimer(const uintptr_t id) noexcept
591 {
592 return static_cast<Status>(puglStopTimer(cobj(), id));
593 }
594
595 /**
596 @}
597 */
598
cobj()599 PuglView* cobj() noexcept { return Wrapper::cobj(); }
cobj() const600 const PuglView* cobj() const noexcept { return Wrapper::cobj(); }
601
602 private:
603 template<class Target>
dispatch(Target & target,const PuglEvent * event)604 static Status dispatch(Target& target, const PuglEvent* event)
605 {
606 switch (event->type) {
607 case PUGL_NOTHING:
608 return Status::success;
609 case PUGL_CREATE:
610 return target.onEvent(static_cast<const CreateEvent&>(event->any));
611 case PUGL_DESTROY:
612 return target.onEvent(static_cast<const DestroyEvent&>(event->any));
613 case PUGL_CONFIGURE:
614 return target.onEvent(
615 static_cast<const ConfigureEvent&>(event->configure));
616 case PUGL_MAP:
617 return target.onEvent(static_cast<const MapEvent&>(event->any));
618 case PUGL_UNMAP:
619 return target.onEvent(static_cast<const UnmapEvent&>(event->any));
620 case PUGL_UPDATE:
621 return target.onEvent(static_cast<const UpdateEvent&>(event->any));
622 case PUGL_EXPOSE:
623 return target.onEvent(static_cast<const ExposeEvent&>(event->expose));
624 case PUGL_CLOSE:
625 return target.onEvent(static_cast<const CloseEvent&>(event->any));
626 case PUGL_FOCUS_IN:
627 return target.onEvent(static_cast<const FocusInEvent&>(event->focus));
628 case PUGL_FOCUS_OUT:
629 return target.onEvent(static_cast<const FocusOutEvent&>(event->focus));
630 case PUGL_KEY_PRESS:
631 return target.onEvent(static_cast<const KeyPressEvent&>(event->key));
632 case PUGL_KEY_RELEASE:
633 return target.onEvent(static_cast<const KeyReleaseEvent&>(event->key));
634 case PUGL_TEXT:
635 return target.onEvent(static_cast<const TextEvent&>(event->text));
636 case PUGL_POINTER_IN:
637 return target.onEvent(
638 static_cast<const PointerInEvent&>(event->crossing));
639 case PUGL_POINTER_OUT:
640 return target.onEvent(
641 static_cast<const PointerOutEvent&>(event->crossing));
642 case PUGL_BUTTON_PRESS:
643 return target.onEvent(
644 static_cast<const ButtonPressEvent&>(event->button));
645 case PUGL_BUTTON_RELEASE:
646 return target.onEvent(
647 static_cast<const ButtonReleaseEvent&>(event->button));
648 case PUGL_MOTION:
649 return target.onEvent(static_cast<const MotionEvent&>(event->motion));
650 case PUGL_SCROLL:
651 return target.onEvent(static_cast<const ScrollEvent&>(event->scroll));
652 case PUGL_CLIENT:
653 return target.onEvent(static_cast<const ClientEvent&>(event->client));
654 case PUGL_TIMER:
655 return target.onEvent(static_cast<const TimerEvent&>(event->timer));
656 case PUGL_LOOP_ENTER:
657 return target.onEvent(static_cast<const LoopEnterEvent&>(event->any));
658 case PUGL_LOOP_LEAVE:
659 return target.onEvent(static_cast<const LoopLeaveEvent&>(event->any));
660 }
661
662 return Status::failure;
663 }
664
665 template<class Target>
eventFunc(PuglView * view,const PuglEvent * event)666 static PuglStatus eventFunc(PuglView* view, const PuglEvent* event) noexcept
667 {
668 auto* target = static_cast<Target*>(puglGetHandle(view));
669
670 #ifdef __cpp_exceptions
671 try {
672 return static_cast<PuglStatus>(dispatch(*target, event));
673 } catch (...) {
674 return PUGL_UNKNOWN_ERROR;
675 }
676 #else
677 return static_cast<PuglStatus>(pugl::dispatch(*target, event));
678 #endif
679 }
680
681 World& _world;
682 };
683
684 /**
685 @}
686 @}
687 */
688
689 } // namespace pugl
690
691 #endif // PUGL_PUGL_HPP
692