User Properties (#2064)

Add the ability to add user-defined properties using a new `openspace.addCustomProperty` function that takes an identifier and a type and creates a new property of that type.  The new property is then available under `UserProperties.<identifier>`
This commit is contained in:
Alexander Bock
2022-05-04 16:06:08 -07:00
committed by GitHub
parent 510e2795de
commit ee735618b4
4 changed files with 195 additions and 1 deletions

View File

@@ -99,6 +99,7 @@ inline interaction::SessionRecording* sessionRecording;
inline interaction::ShortcutManager* shortcutManager;
inline properties::PropertyOwner* rootPropertyOwner;
inline properties::PropertyOwner* screenSpaceRootPropertyOwner;
inline properties::PropertyOwner* userPropertyOwner;
inline scripting::ScriptEngine* scriptEngine;
inline scripting::ScriptScheduler* scriptScheduler;
inline Profile* profile;

View File

@@ -98,6 +98,7 @@ namespace {
sizeof(interaction::SessionRecording) +
sizeof(properties::PropertyOwner) +
sizeof(properties::PropertyOwner) +
sizeof(properties::PropertyOwner) +
sizeof(scripting::ScriptEngine) +
sizeof(scripting::ScriptScheduler) +
sizeof(Profile);
@@ -345,6 +346,14 @@ void create() {
screenSpaceRootPropertyOwner = new properties::PropertyOwner({ "ScreenSpace" });
#endif // WIN32
#ifdef WIN32
userPropertyOwner = new (currentPos) properties::PropertyOwner({ "UserProperties" });
ghoul_assert(userPropertyOwner, "No userPropertyOwner");
currentPos += sizeof(properties::PropertyOwner);
#else // ^^^ WIN32 / !WIN32 vvv
userPropertyOwner = new properties::PropertyOwner({ "UserProperties" });
#endif // WIN32
#ifdef WIN32
scriptEngine = new (currentPos) scripting::ScriptEngine;
ghoul_assert(scriptEngine, "No scriptEngine");
@@ -375,7 +384,6 @@ void initialize() {
rootPropertyOwner->addPropertySubOwner(global::moduleEngine);
navigationHandler->setPropertyOwner(global::rootPropertyOwner);
// New property subowners also have to be added to the ImGuiModule callback!
rootPropertyOwner->addPropertySubOwner(global::navigationHandler);
rootPropertyOwner->addPropertySubOwner(global::interactionMonitor);
@@ -390,6 +398,8 @@ void initialize() {
rootPropertyOwner->addPropertySubOwner(global::luaConsole);
rootPropertyOwner->addPropertySubOwner(global::dashboard);
rootPropertyOwner->addPropertySubOwner(global::userPropertyOwner);
syncEngine->addSyncable(global::scriptEngine);
}

View File

@@ -879,6 +879,8 @@ scripting::LuaLibrary Scene::luaLibrary() {
"Returns a list of property identifiers that match the passed regular "
"expression"
},
codegen::lua::AddCustomProperty,
codegen::lua::RemoveCustomProperty,
codegen::lua::AddSceneGraphNode,
codegen::lua::RemoveSceneGraphNode,
codegen::lua::RemoveSceneGraphNodesFromRegex,

View File

@@ -22,6 +22,36 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/engine/globals.h>
#include <openspace/properties/propertyowner.h>
#include <openspace/properties/matrix/dmat2property.h>
#include <openspace/properties/matrix/dmat3property.h>
#include <openspace/properties/matrix/dmat4property.h>
#include <openspace/properties/matrix/mat2property.h>
#include <openspace/properties/matrix/mat3property.h>
#include <openspace/properties/matrix/mat4property.h>
#include <openspace/properties/scalar/boolproperty.h>
#include <openspace/properties/scalar/doubleproperty.h>
#include <openspace/properties/scalar/floatproperty.h>
#include <openspace/properties/scalar/intproperty.h>
#include <openspace/properties/scalar/longproperty.h>
#include <openspace/properties/scalar/shortproperty.h>
#include <openspace/properties/scalar/uintproperty.h>
#include <openspace/properties/scalar/ulongproperty.h>
#include <openspace/properties/scalar/ushortproperty.h>
#include <openspace/properties/vector/dvec2property.h>
#include <openspace/properties/vector/dvec3property.h>
#include <openspace/properties/vector/dvec4property.h>
#include <openspace/properties/vector/ivec2property.h>
#include <openspace/properties/vector/ivec3property.h>
#include <openspace/properties/vector/ivec4property.h>
#include <openspace/properties/vector/uvec2property.h>
#include <openspace/properties/vector/uvec3property.h>
#include <openspace/properties/vector/uvec4property.h>
#include <openspace/properties/vector/vec2property.h>
#include <openspace/properties/vector/vec3property.h>
#include <openspace/properties/vector/vec4property.h>
namespace {
template <class T>
@@ -917,6 +947,157 @@ namespace {
return is;
}
template <typename T>
void createCustomProperty(openspace::properties::Property::PropertyInfo info,
std::optional<std::string> onChange)
{
T* p = new T(info);
if (onChange.has_value()) {
p->onChange(
[p, script = *onChange]() {
using namespace ghoul::lua;
LuaState s;
openspace::global::scriptEngine->initializeLuaState(s);
ghoul::lua::push(s, p->value());
lua_setglobal(s, "value");
ghoul::lua::runScript(s, script);
}
);
}
openspace::global::userPropertyOwner->addProperty(p);
}
[[codegen::luawrap]] void addCustomProperty(std::string identifier, std::string type,
std::optional<std::string> guiName,
std::optional<std::string> description,
std::optional<std::string> onChange)
{
using namespace openspace;
if (identifier.empty()) {
throw ghoul::lua::LuaError("Identifier must not empty");
}
if (global::userPropertyOwner->hasProperty(identifier)) {
throw ghoul::lua::LuaError(fmt::format(
"Failed to register property '{}' since a user-defined property with that "
"name already exists",
identifier
));
}
// @TODO (abock, 2022-05-01) These if statements here are a bit gnarly since it
// requires us to update them as soon as we add a new property type. It would be nicer
// to have a factory function for this but right now this is the only place where that
// factory would be used.
const char* gui =
guiName.has_value() && !guiName->empty() ?
guiName->c_str() :
identifier.c_str();
properties::Property::PropertyInfo info = {
identifier.c_str(),
gui,
description.has_value() ? description->c_str() : ""
};
if (type == "DMat2Property") {
createCustomProperty<properties::DMat2Property>(info, std::move(onChange));
}
else if (type == "DMat3Property") {
createCustomProperty<properties::DMat3Property>(info, std::move(onChange));
}
else if (type == "DMat4Property") {
createCustomProperty<properties::DMat4Property>(info, std::move(onChange));
}
else if (type == "Mat2Property") {
createCustomProperty<properties::Mat2Property>(info, std::move(onChange));
}
else if (type == "Mat3Property") {
createCustomProperty<properties::Mat3Property>(info, std::move(onChange));
}
else if (type == "Mat4Property") {
createCustomProperty<properties::Mat4Property>(info, std::move(onChange));
}
else if (type == "BoolProperty") {
createCustomProperty<properties::BoolProperty>(info, std::move(onChange));
}
else if (type == "DoubleProperty") {
createCustomProperty<properties::DoubleProperty>(info, std::move(onChange));
}
else if (type == "FloatProperty") {
createCustomProperty<properties::FloatProperty>(info, std::move(onChange));
}
else if (type == "IntProperty") {
createCustomProperty<properties::IntProperty>(info, std::move(onChange));
}
else if (type == "LongProperty") {
createCustomProperty<properties::LongProperty>(info, std::move(onChange));
}
else if (type == "ShortProperty") {
createCustomProperty<properties::ShortProperty>(info, std::move(onChange));
}
else if (type == "UIntProperty") {
createCustomProperty<properties::UIntProperty>(info, std::move(onChange));
}
else if (type == "ULongProperty") {
createCustomProperty<properties::ULongProperty>(info, std::move(onChange));
}
else if (type == "UShortProperty") {
createCustomProperty<properties::UShortProperty>(info, std::move(onChange));
}
else if (type == "DVec2Property") {
createCustomProperty<properties::DVec2Property>(info, std::move(onChange));
}
else if (type == "DVec3Property") {
createCustomProperty<properties::DVec3Property>(info, std::move(onChange));
}
else if (type == "DVec4Property") {
createCustomProperty<properties::DVec4Property>(info, std::move(onChange));
}
else if (type == "IVec2Property") {
createCustomProperty<properties::IVec2Property>(info, std::move(onChange));
}
else if (type == "IVec3Property") {
createCustomProperty<properties::IVec3Property>(info, std::move(onChange));
}
else if (type == "IVec4Property") {
createCustomProperty<properties::IVec4Property>(info, std::move(onChange));
}
else if (type == "UVec2Property") {
createCustomProperty<properties::UVec2Property>(info, std::move(onChange));
}
else if (type == "UVec3Property") {
createCustomProperty<properties::UVec3Property>(info, std::move(onChange));
}
else if (type == "UVec4Property") {
createCustomProperty<properties::UVec4Property>(info, std::move(onChange));
}
else if (type == "Vec2Property") {
createCustomProperty<properties::Vec2Property>(info, std::move(onChange));
}
else if (type == "Vec3Property") {
createCustomProperty<properties::Vec3Property>(info, std::move(onChange));
}
else if (type == "Vec4Property") {
createCustomProperty<properties::Vec4Property>(info, std::move(onChange));
}
}
[[codegen::luawrap]] void removeCustomProperty(std::string identifier) {
using namespace openspace;
properties::Property* p = global::userPropertyOwner->property(identifier);
if (p) {
global::userPropertyOwner->removeProperty(p);
delete p;
}
else {
throw ghoul::lua::LuaError(fmt::format(
"Could not find user-defined property '{}'", identifier
));
}
}
} // namespace
#include "scene_lua_codegen.cpp"