diff --git a/panda/src/event/CMakeLists.txt b/panda/src/event/CMakeLists.txt index b0464ff793..47136d1b5e 100644 --- a/panda/src/event/CMakeLists.txt +++ b/panda/src/event/CMakeLists.txt @@ -9,6 +9,7 @@ set(P3EVENT_HEADERS config_event.h buttonEvent.I buttonEvent.h buttonEventList.I buttonEventList.h + functionAsyncTask.h functionAsyncTask.I genericAsyncTask.h genericAsyncTask.I pointerEvent.I pointerEvent.h pointerEventList.I pointerEventList.h @@ -28,6 +29,7 @@ set(P3EVENT_SOURCES asyncTaskSequence.cxx buttonEvent.cxx buttonEventList.cxx + functionAsyncTask.cxx genericAsyncTask.cxx pointerEvent.cxx pointerEventList.cxx diff --git a/panda/src/event/asyncTaskManager.I b/panda/src/event/asyncTaskManager.I index 8cf788dc9e..4af23b4bcf 100644 --- a/panda/src/event/asyncTaskManager.I +++ b/panda/src/event/asyncTaskManager.I @@ -32,6 +32,19 @@ get_clock() { return _clock; } +#ifndef CPPPARSER +/** + * Adds a new task which calls the indicated function to the task manager. + * Returns the newly created FunctionAsyncTask object. + */ +INLINE AsyncTask *AsyncTaskManager:: +add(const std::string &name, FunctionAsyncTask::TaskFunction function) { + AsyncTask *task = new FunctionAsyncTask(name, std::move(function)); + add(task); + return task; +} +#endif + /** * Returns the number of tasks that are currently active or sleeping within * the task manager. diff --git a/panda/src/event/asyncTaskManager.h b/panda/src/event/asyncTaskManager.h index 0bb137deb4..0982e5e2c7 100644 --- a/panda/src/event/asyncTaskManager.h +++ b/panda/src/event/asyncTaskManager.h @@ -30,6 +30,7 @@ #include "clockObject.h" #include "ordered_vector.h" #include "indirectCompareNames.h" +#include "functionAsyncTask.h" /** * A class to manage a loose queue of isolated tasks, which can be performed @@ -64,6 +65,9 @@ PUBLISHED: BLOCKING bool remove_task_chain(const std::string &name); void add(AsyncTask *task); +#ifndef CPPPARSER + INLINE AsyncTask *add(const std::string &name, FunctionAsyncTask::TaskFunction function); +#endif bool has_task(AsyncTask *task) const; AsyncTask *find_task(const std::string &name) const; diff --git a/panda/src/event/config_event.cxx b/panda/src/event/config_event.cxx index ccae0d95ae..93dc8d916b 100644 --- a/panda/src/event/config_event.cxx +++ b/panda/src/event/config_event.cxx @@ -22,6 +22,7 @@ #include "event.h" #include "eventHandler.h" #include "eventParameter.h" +#include "functionAsyncTask.h" #include "genericAsyncTask.h" #include "pointerEventList.h" @@ -49,6 +50,7 @@ ConfigureFn(config_event) { EventHandler::init_type(); EventStoreInt::init_type("EventStoreInt"); EventStoreDouble::init_type("EventStoreDouble"); + FunctionAsyncTask::init_type(); GenericAsyncTask::init_type(); ButtonEventList::register_with_read_factory(); diff --git a/panda/src/event/functionAsyncTask.I b/panda/src/event/functionAsyncTask.I new file mode 100644 index 0000000000..aa413dacf0 --- /dev/null +++ b/panda/src/event/functionAsyncTask.I @@ -0,0 +1,83 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file functionAsyncTask.I + * @author rdb + * @date 2021-11-29 + */ + +/** + * + */ +INLINE FunctionAsyncTask:: +FunctionAsyncTask(const std::string &name) : + AsyncTask(name) +{ +} + +/** + * + */ +INLINE FunctionAsyncTask:: +FunctionAsyncTask(const std::string &name, FunctionAsyncTask::TaskFunction function) : + AsyncTask(name), + _function(std::move(function)) +{ +} + +/** + * Replaces the function that is called when the task runs. + */ +INLINE void FunctionAsyncTask:: +set_function(TaskFunction function) { + _function = std::move(function); +} + +/** + * Returns the function that is called when the task runs. + */ +INLINE const FunctionAsyncTask::TaskFunction &FunctionAsyncTask:: +get_function() const { + return _function; +} + +/** + * Replaces the function that is called when the task begins. This is an + * optional function. + */ +INLINE void FunctionAsyncTask:: +set_upon_birth(BirthFunction upon_birth) { + _upon_birth = std::move(upon_birth); +} + +/** + * Returns the function that is called when the task begins, or NULL if the + * function is not defined. + */ +INLINE const FunctionAsyncTask::BirthFunction &FunctionAsyncTask:: +get_upon_birth() const { + return _upon_birth; +} + +/** + * Replaces the function that is called when the task ends. This is an + * optional function. + */ +INLINE void FunctionAsyncTask:: +set_upon_death(FunctionAsyncTask::DeathFunction upon_death) { + _upon_death = upon_death; +} + +/** + * Returns the function that is called when the task ends, or NULL if the + * function is not defined. + */ +INLINE const FunctionAsyncTask::DeathFunction &FunctionAsyncTask:: +get_upon_death() const { + return _upon_death; +} diff --git a/panda/src/event/functionAsyncTask.cxx b/panda/src/event/functionAsyncTask.cxx new file mode 100644 index 0000000000..54b591918d --- /dev/null +++ b/panda/src/event/functionAsyncTask.cxx @@ -0,0 +1,81 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file functionAsyncTask.cxx + * @author rdb + * @date 2021-11-29 + */ + +#include "functionAsyncTask.h" +#include "pnotify.h" + +#ifndef CPPPARSER + +TypeHandle FunctionAsyncTask::_type_handle; + +/** + * Override this function to return true if the task can be successfully + * executed, false if it cannot. Mainly intended as a sanity check when + * attempting to add the task to a task manager. + * + * This function is called with the lock held. + */ +bool FunctionAsyncTask:: +is_runnable() { + return !!_function; +} + +/** + * Override this function to do something useful for the task. + * + * This function is called with the lock *not* held. + */ +AsyncTask::DoneStatus FunctionAsyncTask:: +do_task() { + nassertr(_function, DS_interrupt); + return _function(this); +} + +/** + * Override this function to do something useful when the task has been added + * to the active queue. + * + * This function is called with the lock *not* held. + */ +void FunctionAsyncTask:: +upon_birth(AsyncTaskManager *manager) { + AsyncTask::upon_birth(manager); + + if (_upon_birth) { + _upon_birth(this); + } +} + +/** + * Override this function to do something useful when the task has been + * removed from the active queue. The parameter clean_exit is true if the + * task has been removed because it exited normally (returning DS_done), or + * false if it was removed for some other reason (e.g. + * AsyncTaskManager::remove()). By the time this method is called, _manager + * has been cleared, so the parameter manager indicates the original + * AsyncTaskManager that owned this task. + * + * The normal behavior is to throw the done_event only if clean_exit is true. + * + * This function is called with the lock *not* held. + */ +void FunctionAsyncTask:: +upon_death(AsyncTaskManager *manager, bool clean_exit) { + AsyncTask::upon_death(manager, clean_exit); + + if (_upon_death) { + _upon_death(this, clean_exit); + } +} + +#endif // CPPPARSER diff --git a/panda/src/event/functionAsyncTask.h b/panda/src/event/functionAsyncTask.h new file mode 100644 index 0000000000..297d71c691 --- /dev/null +++ b/panda/src/event/functionAsyncTask.h @@ -0,0 +1,83 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file functionAsyncTask.h + * @author rdb + * @date 2021-11-29 + */ + +#ifndef FUNCTIONASYNCTASK_H +#define FUNCTIONASYNCTASK_H + +#include "pandabase.h" + +#include "asyncTask.h" + +#ifndef CPPPARSER +#include + +/** + * Associates a generic std::function (eg. a lambda) with an AsyncTask object. + * You can use this when you want to create an AsyncTask without having to + * subclass. + * + * @since 1.11.0 + */ +class EXPCL_PANDA_EVENT FunctionAsyncTask final : public AsyncTask { +public: + typedef std::function TaskFunction; + typedef std::function BirthFunction; + typedef std::function DeathFunction; + + INLINE FunctionAsyncTask(const std::string &name = std::string()); + INLINE FunctionAsyncTask(const std::string &name, TaskFunction function); + ALLOC_DELETED_CHAIN(FunctionAsyncTask); + + INLINE void set_function(TaskFunction function); + INLINE const TaskFunction &get_function() const; + + INLINE void set_upon_birth(BirthFunction function); + INLINE const BirthFunction &get_upon_birth() const; + + INLINE void set_upon_death(DeathFunction function); + INLINE const DeathFunction &get_upon_death() const; + +protected: + virtual bool is_runnable() override; + virtual DoneStatus do_task() override; + virtual void upon_birth(AsyncTaskManager *manager) override; + virtual void upon_death(AsyncTaskManager *manager, bool clean_exit) override; + +private: + TaskFunction _function; + BirthFunction _upon_birth; + DeathFunction _upon_death; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + AsyncTask::init_type(); + register_type(_type_handle, "FunctionAsyncTask", + AsyncTask::get_class_type()); + } + virtual TypeHandle get_type() const override { + return get_class_type(); + } + virtual TypeHandle force_init_type() override {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; +}; + +#include "functionAsyncTask.I" + +#endif // CPPPARSER + +#endif diff --git a/panda/src/event/genericAsyncTask.h b/panda/src/event/genericAsyncTask.h index f35d780e3b..ce7f635156 100644 --- a/panda/src/event/genericAsyncTask.h +++ b/panda/src/event/genericAsyncTask.h @@ -22,6 +22,8 @@ * Associates a generic C-style function pointer with an AsyncTask object. * You can use this when you want to create an AsyncTask without having to * subclass. + * + * @deprecated See FunctionAsyncTask instead, which is more powerful. */ class EXPCL_PANDA_EVENT GenericAsyncTask : public AsyncTask { public: diff --git a/panda/src/event/p3event_composite1.cxx b/panda/src/event/p3event_composite1.cxx index dc72d2b03f..34fcb9a0c9 100644 --- a/panda/src/event/p3event_composite1.cxx +++ b/panda/src/event/p3event_composite1.cxx @@ -7,6 +7,7 @@ #include "asyncTaskSequence.cxx" #include "buttonEvent.cxx" #include "buttonEventList.cxx" +#include "functionAsyncTask.cxx" #include "genericAsyncTask.cxx" #include "pointerEvent.cxx" #include "pointerEventList.cxx" diff --git a/panda/src/framework/windowFramework.cxx b/panda/src/framework/windowFramework.cxx index 454729889b..ae10964b54 100644 --- a/panda/src/framework/windowFramework.cxx +++ b/panda/src/framework/windowFramework.cxx @@ -1429,8 +1429,11 @@ create_anim_controls() { setup_shuttle_button("4", 2, st_play_button); setup_shuttle_button(":", 3, st_forward_button); - _update_anim_controls_task = new GenericAsyncTask("controls", st_update_anim_controls, (void *)this); - _panda_framework->get_task_mgr().add(_update_anim_controls_task); + AsyncTaskManager &task_mgr = _panda_framework->get_task_mgr(); + _update_anim_controls_task = task_mgr.add("controls", [this](AsyncTask *task) { + update_anim_controls(); + return AsyncTask::DS_cont; + }); } /** @@ -1443,7 +1446,7 @@ destroy_anim_controls() { _panda_framework->get_event_handler().remove_hooks_with((void *)this); if (_update_anim_controls_task != nullptr) { - _panda_framework->get_task_mgr().remove(_update_anim_controls_task); + _update_anim_controls_task->remove(); _update_anim_controls_task.clear(); } } @@ -1559,18 +1562,6 @@ forward_button() { control->pose(control->get_frame() + 1); } - -/** - * The static task function. - */ -AsyncTask::DoneStatus WindowFramework:: -st_update_anim_controls(GenericAsyncTask *, void *data) { - WindowFramework *self = (WindowFramework *)data; - self->update_anim_controls(); - return AsyncTask::DS_cont; -} - - /** * The static event handler function. */ diff --git a/panda/src/framework/windowFramework.h b/panda/src/framework/windowFramework.h index b6e93041eb..782989aad9 100644 --- a/panda/src/framework/windowFramework.h +++ b/panda/src/framework/windowFramework.h @@ -154,8 +154,6 @@ private: void play_button(); void forward_button(); - static AsyncTask::DoneStatus st_update_anim_controls(GenericAsyncTask *task, void *data); - static void st_back_button(const Event *, void *data); static void st_pause_button(const Event *, void *data); static void st_play_button(const Event *, void *data); @@ -183,7 +181,7 @@ private: PT(PGSliderBar) _anim_slider; PT(PGSliderBar) _play_rate_slider; PT(TextNode) _frame_number; - PT(GenericAsyncTask) _update_anim_controls_task; + PT(AsyncTask) _update_anim_controls_task; NodePath _mouse; NodePath _button_thrower;