aboutsummaryrefslogtreecommitdiffstats
path: root/bindings/cxx/include/pugl/pugl.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'bindings/cxx/include/pugl/pugl.hpp')
-rw-r--r--bindings/cxx/include/pugl/pugl.hpp170
1 files changed, 99 insertions, 71 deletions
diff --git a/bindings/cxx/include/pugl/pugl.hpp b/bindings/cxx/include/pugl/pugl.hpp
index 54c0648..dde29c8 100644
--- a/bindings/cxx/include/pugl/pugl.hpp
+++ b/bindings/cxx/include/pugl/pugl.hpp
@@ -353,8 +353,14 @@ enum class Cursor {
static_assert(Cursor(PUGL_CURSOR_UP_DOWN) == Cursor::upDown, "");
-/// @copydoc PuglView
-class View : protected detail::Wrapper<PuglView, puglFreeView>
+/**
+ A drawable region that receives events.
+
+ This is the generic base class for all views. It can be used directly by
+ manually setting an event handling function, but typical applications should
+ use pugl::View which handles dispatching events.
+*/
+class ViewBase : protected detail::Wrapper<PuglView, puglFreeView>
{
public:
/**
@@ -363,26 +369,13 @@ public:
@{
*/
- explicit View(World& world)
+ explicit ViewBase(World& world)
: Wrapper{puglNewView(world.cobj())}
, _world(world)
{
- if (cobj()) {
- puglSetHandle(cobj(), this);
- puglSetEventFunc(cobj(), dispatchEvent);
- }
-
PUGL_CHECK_CONSTRUCTION(cobj(), "Failed to create pugl::View");
}
- virtual ~View() noexcept = default;
-
- View(const View&) = delete;
- View& operator=(const View&) = delete;
-
- View(View&&) = delete;
- View&& operator=(View&&) = delete;
-
const World& world() const noexcept { return _world; }
World& world() noexcept { return _world; }
@@ -559,6 +552,38 @@ public:
return static_cast<Status>(puglStopTimer(cobj(), id));
}
+ PuglView* cobj() noexcept { return Wrapper::cobj(); }
+ const PuglView* cobj() const noexcept { return Wrapper::cobj(); }
+
+private:
+ World& _world;
+};
+
+/**
+ A view with event handlers.
+
+ To implement a view, applications can inherit from this class, which handles
+ type-safe dispatching of events to methods. This class uses the CRTP
+ pattern, so the name of the derived class needs to be passed as a template
+ paramter, for example:
+
+ @code
+ class MyView : public pugl::View<MyView>
+ @endcode
+*/
+template<class Derived>
+class View : public ViewBase
+{
+public:
+ explicit View(World& world)
+ : ViewBase{world}
+ {
+ if (cobj()) {
+ puglSetHandle(cobj(), this);
+ puglSetEventFunc(cobj(), eventFunc);
+ }
+ }
+
/**
@}
@name Event Handlers
@@ -566,40 +591,45 @@ public:
@{
*/
- virtual Status onCreate(const CreateEvent&) PUGL_CONST_FUNC;
- virtual Status onDestroy(const DestroyEvent&) PUGL_CONST_FUNC;
- virtual Status onConfigure(const ConfigureEvent&) PUGL_CONST_FUNC;
- virtual Status onMap(const MapEvent&) PUGL_CONST_FUNC;
- virtual Status onUnmap(const UnmapEvent&) PUGL_CONST_FUNC;
- virtual Status onUpdate(const UpdateEvent&) PUGL_CONST_FUNC;
- virtual Status onExpose(const ExposeEvent&) PUGL_CONST_FUNC;
- virtual Status onClose(const CloseEvent&) PUGL_CONST_FUNC;
- virtual Status onFocusIn(const FocusInEvent&) PUGL_CONST_FUNC;
- virtual Status onFocusOut(const FocusOutEvent&) PUGL_CONST_FUNC;
- virtual Status onKeyPress(const KeyPressEvent&) PUGL_CONST_FUNC;
- virtual Status onKeyRelease(const KeyReleaseEvent&) PUGL_CONST_FUNC;
- virtual Status onText(const TextEvent&) PUGL_CONST_FUNC;
- virtual Status onPointerIn(const PointerInEvent&) PUGL_CONST_FUNC;
- virtual Status onPointerOut(const PointerOutEvent&) PUGL_CONST_FUNC;
- virtual Status onButtonPress(const ButtonPressEvent&) PUGL_CONST_FUNC;
- virtual Status onButtonRelease(const ButtonReleaseEvent&) PUGL_CONST_FUNC;
- virtual Status onMotion(const MotionEvent&) PUGL_CONST_FUNC;
- virtual Status onScroll(const ScrollEvent&) PUGL_CONST_FUNC;
- virtual Status onClient(const ClientEvent&) PUGL_CONST_FUNC;
- virtual Status onTimer(const TimerEvent&) PUGL_CONST_FUNC;
- virtual Status onLoopEnter(const LoopEnterEvent&) PUGL_CONST_FUNC;
- virtual Status onLoopLeave(const LoopLeaveEvent&) PUGL_CONST_FUNC;
+ Status onEvent(const CreateEvent&) noexcept { return Status::success; }
+ Status onEvent(const DestroyEvent&) noexcept { return Status::success; }
+ Status onEvent(const ConfigureEvent&) noexcept { return Status::success; }
+ Status onEvent(const MapEvent&) noexcept { return Status::success; }
+ Status onEvent(const UnmapEvent&) noexcept { return Status::success; }
+ Status onEvent(const UpdateEvent&) noexcept { return Status::success; }
+ Status onEvent(const ExposeEvent&) noexcept { return Status::success; }
+ Status onEvent(const CloseEvent&) noexcept { return Status::success; }
+ Status onEvent(const FocusInEvent&) noexcept { return Status::success; }
+ Status onEvent(const FocusOutEvent&) noexcept { return Status::success; }
+ Status onEvent(const KeyPressEvent&) noexcept { return Status::success; }
+ Status onEvent(const KeyReleaseEvent&) noexcept { return Status::success; }
+ Status onEvent(const TextEvent&) noexcept { return Status::success; }
+ Status onEvent(const PointerInEvent&) noexcept { return Status::success; }
+ Status onEvent(const PointerOutEvent&) noexcept { return Status::success; }
+ Status onEvent(const ButtonPressEvent&) noexcept { return Status::success; }
+ Status onEvent(const ButtonReleaseEvent&) noexcept
+ {
+ return Status::success;
+ }
+ Status onEvent(const MotionEvent&) noexcept { return Status::success; }
+ Status onEvent(const ScrollEvent&) noexcept { return Status::success; }
+ Status onEvent(const ClientEvent&) noexcept { return Status::success; }
+ Status onEvent(const TimerEvent&) noexcept { return Status::success; }
+ Status onEvent(const LoopEnterEvent&) noexcept { return Status::success; }
+ Status onEvent(const LoopLeaveEvent&) noexcept { return Status::success; }
/**
@}
*/
- PuglView* cobj() noexcept { return Wrapper::cobj(); }
- const PuglView* cobj() const noexcept { return Wrapper::cobj(); }
-
private:
- static PuglStatus
- dispatchEvent(PuglView* view, const PuglEvent* event) noexcept
+ Derived& self() noexcept { return *static_cast<Derived*>(this); }
+ const Derived& self() const noexcept
+ {
+ return *static_cast<Derived*>(this);
+ }
+
+ static PuglStatus eventFunc(PuglView* view, const PuglEvent* event) noexcept
{
View* self = static_cast<View*>(puglGetHandle(view));
@@ -621,79 +651,77 @@ private:
return PUGL_SUCCESS;
case PUGL_CREATE:
return static_cast<PuglStatus>(
- onCreate(static_cast<const CreateEvent&>(event->any)));
+ self().onEvent(static_cast<const CreateEvent&>(event->any)));
case PUGL_DESTROY:
return static_cast<PuglStatus>(
- onDestroy(static_cast<const DestroyEvent&>(event->any)));
+ self().onEvent(static_cast<const DestroyEvent&>(event->any)));
case PUGL_CONFIGURE:
- return static_cast<PuglStatus>(onConfigure(
+ return static_cast<PuglStatus>(self().onEvent(
static_cast<const ConfigureEvent&>(event->configure)));
case PUGL_MAP:
return static_cast<PuglStatus>(
- onMap(static_cast<const MapEvent&>(event->any)));
+ self().onEvent(static_cast<const MapEvent&>(event->any)));
case PUGL_UNMAP:
return static_cast<PuglStatus>(
- onUnmap(static_cast<const UnmapEvent&>(event->any)));
+ self().onEvent(static_cast<const UnmapEvent&>(event->any)));
case PUGL_UPDATE:
return static_cast<PuglStatus>(
- onUpdate(static_cast<const UpdateEvent&>(event->any)));
+ self().onEvent(static_cast<const UpdateEvent&>(event->any)));
case PUGL_EXPOSE:
return static_cast<PuglStatus>(
- onExpose(static_cast<const ExposeEvent&>(event->expose)));
+ self().onEvent(static_cast<const ExposeEvent&>(event->expose)));
case PUGL_CLOSE:
return static_cast<PuglStatus>(
- onClose(static_cast<const CloseEvent&>(event->any)));
+ self().onEvent(static_cast<const CloseEvent&>(event->any)));
case PUGL_FOCUS_IN:
return static_cast<PuglStatus>(
- onFocusIn(static_cast<const FocusInEvent&>(event->focus)));
+ self().onEvent(static_cast<const FocusInEvent&>(event->focus)));
case PUGL_FOCUS_OUT:
- return static_cast<PuglStatus>(
- onFocusOut(static_cast<const FocusOutEvent&>(event->focus)));
+ return static_cast<PuglStatus>(self().onEvent(
+ static_cast<const FocusOutEvent&>(event->focus)));
case PUGL_KEY_PRESS:
return static_cast<PuglStatus>(
- onKeyPress(static_cast<const KeyPressEvent&>(event->key)));
+ self().onEvent(static_cast<const KeyPressEvent&>(event->key)));
case PUGL_KEY_RELEASE:
- return static_cast<PuglStatus>(
- onKeyRelease(static_cast<const KeyReleaseEvent&>(event->key)));
+ return static_cast<PuglStatus>(self().onEvent(
+ static_cast<const KeyReleaseEvent&>(event->key)));
case PUGL_TEXT:
return static_cast<PuglStatus>(
- onText(static_cast<const TextEvent&>(event->text)));
+ self().onEvent(static_cast<const TextEvent&>(event->text)));
case PUGL_POINTER_IN:
- return static_cast<PuglStatus>(onPointerIn(
+ return static_cast<PuglStatus>(self().onEvent(
static_cast<const PointerInEvent&>(event->crossing)));
case PUGL_POINTER_OUT:
- return static_cast<PuglStatus>(onPointerOut(
+ return static_cast<PuglStatus>(self().onEvent(
static_cast<const PointerOutEvent&>(event->crossing)));
case PUGL_BUTTON_PRESS:
- return static_cast<PuglStatus>(onButtonPress(
+ return static_cast<PuglStatus>(self().onEvent(
static_cast<const ButtonPressEvent&>(event->button)));
case PUGL_BUTTON_RELEASE:
- return static_cast<PuglStatus>(onButtonRelease(
+ return static_cast<PuglStatus>(self().onEvent(
static_cast<const ButtonReleaseEvent&>(event->button)));
case PUGL_MOTION:
return static_cast<PuglStatus>(
- onMotion(static_cast<const MotionEvent&>(event->motion)));
+ self().onEvent(static_cast<const MotionEvent&>(event->motion)));
case PUGL_SCROLL:
return static_cast<PuglStatus>(
- onScroll(static_cast<const ScrollEvent&>(event->scroll)));
+ self().onEvent(static_cast<const ScrollEvent&>(event->scroll)));
case PUGL_CLIENT:
return static_cast<PuglStatus>(
- onClient(static_cast<const ClientEvent&>(event->client)));
+ self().onEvent(static_cast<const ClientEvent&>(event->client)));
case PUGL_TIMER:
return static_cast<PuglStatus>(
- onTimer(static_cast<const TimerEvent&>(event->timer)));
+ self().onEvent(static_cast<const TimerEvent&>(event->timer)));
case PUGL_LOOP_ENTER:
return static_cast<PuglStatus>(
- onLoopEnter(static_cast<const LoopEnterEvent&>(event->any)));
+ self().onEvent(static_cast<const LoopEnterEvent&>(event->any)));
case PUGL_LOOP_LEAVE:
return static_cast<PuglStatus>(
- onLoopLeave(static_cast<const LoopLeaveEvent&>(event->any)));
+ self().onEvent(static_cast<const LoopLeaveEvent&>(event->any)));
}
return PUGL_FAILURE;
}
-
- World& _world;
};
/**