diff --git a/scenarios/ArVizExample/config/ArVizInteractExample.cfg b/scenarios/ArVizExample/config/ArVizInteractExample.cfg new file mode 100644 index 0000000000000000000000000000000000000000..0892ab764555b0fba8759653513371035dc9b45d --- /dev/null +++ b/scenarios/ArVizExample/config/ArVizInteractExample.cfg @@ -0,0 +1,204 @@ +# ================================================================== +# ArVizInteractExample properties +# ================================================================== + +# ArmarX.AdditionalPackages: List of additional ArmarX packages which should be in the list of default packages. If you have custom packages, which should be found by the gui or other apps, specify them here. Comma separated List. +# Attributes: +# - Default: Default value not mapped. +# - Case sensitivity: yes +# - Required: no +# ArmarX.AdditionalPackages = Default value not mapped. + + +# ArmarX.ApplicationName: Application name +# Attributes: +# - Default: "" +# - Case sensitivity: yes +# - Required: no +# ArmarX.ApplicationName = "" + + +# ArmarX.ArVizInteractExample.ArVizStorageName: Name of the ArViz storage +# Attributes: +# - Default: ArVizStorage +# - Case sensitivity: yes +# - Required: no +# ArmarX.ArVizInteractExample.ArVizStorageName = ArVizStorage + + +# ArmarX.ArVizInteractExample.ArVizTopicName: Name of the ArViz topic +# Attributes: +# - Default: ArVizTopic +# - Case sensitivity: yes +# - Required: no +# ArmarX.ArVizInteractExample.ArVizTopicName = ArVizTopic + + +# ArmarX.ArVizInteractExample.EnableProfiling: enable profiler which is used for logging performance events +# Attributes: +# - Default: false +# - Case sensitivity: yes +# - Required: no +# - Possible values: {0, 1, false, no, true, yes} +# ArmarX.ArVizInteractExample.EnableProfiling = false + + +# ArmarX.ArVizInteractExample.MinimumLoggingLevel: Local logging level only for this component +# Attributes: +# - Default: Undefined +# - Case sensitivity: yes +# - Required: no +# - Possible values: {Debug, Error, Fatal, Important, Info, Undefined, Verbose, Warning} +# ArmarX.ArVizInteractExample.MinimumLoggingLevel = Undefined + + +# ArmarX.ArVizInteractExample.ObjectName: Name of IceGrid well-known object +# Attributes: +# - Default: "" +# - Case sensitivity: yes +# - Required: no +# ArmarX.ArVizInteractExample.ObjectName = "" + + +# ArmarX.CachePath: Path for cache files. If relative path AND env. variable ARMARX_CONFIG_DIR is set, the cache path will be made relative to ARMARX_CONFIG_DIR. Otherwise if relative it will be relative to the default ArmarX config dir (${ARMARX_WORKSPACE}/armarx_config) +# Attributes: +# - Default: mongo/.cache +# - Case sensitivity: yes +# - Required: no +# ArmarX.CachePath = mongo/.cache + + +# ArmarX.Config: Comma-separated list of configuration files +# Attributes: +# - Default: "" +# - Case sensitivity: yes +# - Required: no +# ArmarX.Config = "" + + +# ArmarX.DataPath: Semicolon-separated search list for data files +# Attributes: +# - Default: "" +# - Case sensitivity: yes +# - Required: no +# ArmarX.DataPath = "" + + +# ArmarX.DefaultPackages: List of ArmarX packages which are accessible by default. Comma separated List. If you want to add your own packages and use all default ArmarX packages, use the property 'AdditionalPackages'. +# Attributes: +# - Default: Default value not mapped. +# - Case sensitivity: yes +# - Required: no +# ArmarX.DefaultPackages = Default value not mapped. + + +# ArmarX.DependenciesConfig: Path to the (usually generated) config file containing all data paths of all dependent projects. This property usually does not need to be edited. +# Attributes: +# - Default: ./config/dependencies.cfg +# - Case sensitivity: yes +# - Required: no +# ArmarX.DependenciesConfig = ./config/dependencies.cfg + + +# ArmarX.DisableLogging: Turn logging off in whole application +# Attributes: +# - Default: false +# - Case sensitivity: yes +# - Required: no +# - Possible values: {0, 1, false, no, true, yes} +# ArmarX.DisableLogging = false + + +# ArmarX.EnableProfiling: Enable profiling of CPU load produced by this application +# Attributes: +# - Default: false +# - Case sensitivity: yes +# - Required: no +# - Possible values: {0, 1, false, no, true, yes} +# ArmarX.EnableProfiling = false + + +# ArmarX.LoadLibraries: Libraries to load at start up of the application. Must be enabled by the Application with enableLibLoading(). Format: PackageName:LibraryName;... or /absolute/path/to/library;... +# Attributes: +# - Default: "" +# - Case sensitivity: yes +# - Required: no +# ArmarX.LoadLibraries = "" + + +# ArmarX.LoggingGroup: The logging group is transmitted with every ArmarX log message over Ice in order to group the message in the GUI. +# Attributes: +# - Default: "" +# - Case sensitivity: yes +# - Required: no +# ArmarX.LoggingGroup = "" + + +# ArmarX.RedirectStdout: Redirect std::cout and std::cerr to ArmarXLog +# Attributes: +# - Default: true +# - Case sensitivity: yes +# - Required: no +# - Possible values: {0, 1, false, no, true, yes} +# ArmarX.RedirectStdout = true + + +# ArmarX.RemoteHandlesDeletionTimeout: The timeout (in ms) before a remote handle deletes the managed object after the use count reached 0. This time can be used by a client to increment the count again (may be required when transmitting remote handles) +# Attributes: +# - Default: 3000 +# - Case sensitivity: yes +# - Required: no +# ArmarX.RemoteHandlesDeletionTimeout = 3000 + + +# ArmarX.SecondsStartupDelay: The startup will be delayed by this number of seconds (useful for debugging) +# Attributes: +# - Default: 0 +# - Case sensitivity: yes +# - Required: no +# ArmarX.SecondsStartupDelay = 0 + + +# ArmarX.StartDebuggerOnCrash: If this application crashes (segmentation fault) qtcreator will attach to this process and start the debugger. +# Attributes: +# - Default: false +# - Case sensitivity: yes +# - Required: no +# - Possible values: {0, 1, false, no, true, yes} +# ArmarX.StartDebuggerOnCrash = false + + +# ArmarX.ThreadPoolSize: Size of the ArmarX ThreadPool that is always running. +# Attributes: +# - Default: 1 +# - Case sensitivity: yes +# - Required: no +# ArmarX.ThreadPoolSize = 1 + + +# ArmarX.TopicSuffix: Suffix appended to all topic names for outgoing topics. This is mainly used to direct all topics to another name for TopicReplaying purposes. +# Attributes: +# - Default: "" +# - Case sensitivity: yes +# - Required: no +# ArmarX.TopicSuffix = "" + + +# ArmarX.UseTimeServer: Enable using a global Timeserver (e.g. from ArmarXSimulator) +# Attributes: +# - Default: false +# - Case sensitivity: yes +# - Required: no +# - Possible values: {0, 1, false, no, true, yes} +# ArmarX.UseTimeServer = false + + +# ArmarX.Verbosity: Global logging level for whole application +# Attributes: +# - Default: Info +# - Case sensitivity: yes +# - Required: no +# - Possible values: {Debug, Error, Fatal, Important, Info, Undefined, Verbose, Warning} +# ArmarX.Verbosity = Info + + diff --git a/source/RobotAPI/libraries/CMakeLists.txt b/source/RobotAPI/libraries/CMakeLists.txt index 099ad8b4b981aeed1cc9e274c25672a1014ee120..764c797c11c2bc7e48ad64ca0ee0173197613e92 100644 --- a/source/RobotAPI/libraries/CMakeLists.txt +++ b/source/RobotAPI/libraries/CMakeLists.txt @@ -16,6 +16,7 @@ add_subdirectory(natik) add_subdirectory(ukfm) add_subdirectory(aron) +add_subdirectory(aron_component_config) add_subdirectory(armem) add_subdirectory(armem_grasping) diff --git a/source/RobotAPI/libraries/aron_component_config/CMakeLists.txt b/source/RobotAPI/libraries/aron_component_config/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..f9e545e5c4caceed94f27109f824468e111c742e --- /dev/null +++ b/source/RobotAPI/libraries/aron_component_config/CMakeLists.txt @@ -0,0 +1,58 @@ +#armarx_add_library(AronComponentConfig +# DEPENDENCIES +# ArmarXCoreInterfaces ArmarXCore ArmarXGuiComponentPlugins +# RobotAPIInterfaces RobotAPICore RobotAPIComponentPlugins +# SOURCES +# PropertyDefinitionVisitors.cpp +# RemoteGuiVisitors.cpp +# HEADERS +# PropertyDefinitionVisitors.h +# RemoteGui.h +# RemoteGuiVisitors.h +# Util.h +# ComponentPlugin.h +# ) + +set(LIB_NAME aron_component_config) + +armarx_component_set_name("${LIB_NAME}") +armarx_set_target("Library: ${LIB_NAME}") + +find_package(Simox QUIET) +armarx_build_if(Simox_FOUND "Simox not available") + +set(LIBS + ArmarXCoreInterfaces ArmarXCore ArmarXGuiComponentPlugins + RobotAPIInterfaces RobotAPICore RobotAPIComponentPlugins +) + +set(LIB_FILES + PropertyDefinitionVisitors.cpp + RemoteGuiVisitors.cpp +) + +set(LIB_HEADERS + PropertyDefinitionVisitors.h + RemoteGui.h + RemoteGuiVisitors.h + Util.h + ComponentPlugin.h +) + + +armarx_add_library( + LIB_NAME + "${LIB_NAME}" + SOURCES + "${LIB_FILES}" + HEADERS + "${LIB_HEADERS}" + LIBS + "${LIBS}" +) + +add_library( + RobotAPI::aron_component_config + ALIAS + aron_component_config +) diff --git a/source/RobotAPI/libraries/aron_component_config/ComponentPlugin.h b/source/RobotAPI/libraries/aron_component_config/ComponentPlugin.h new file mode 100644 index 0000000000000000000000000000000000000000..eb3c794e6c3b77d5bc0c71459f7038f7d13c5153 --- /dev/null +++ b/source/RobotAPI/libraries/aron_component_config/ComponentPlugin.h @@ -0,0 +1,157 @@ +/* + * This file is part of ArmarX. + * + * ArmarX is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ArmarX is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @package robdekon + * @author Christoph Pohl ( christoph dot pohl at kit dot edu ) + * @date 07.09.22 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + +#pragma once + +#include <experimental/memory> +#include <ArmarXCore/core/ManagedIceObject.h> +#include <ArmarXCore/core/ComponentPlugin.h> +#include <RobotAPI/libraries/aron/core/codegeneration/cpp/AronGeneratedClass.h> +#include <ArmarXGui/libraries/ArmarXGuiComponentPlugins/RemoteGuiComponentPlugin.h> +#include <RobotAPI/libraries/aron/core/data/visitor/RecursiveVisitor.h> +#include "PropertyDefinitionVisitors.h" +#include "RemoteGui.h" + + +namespace armarx::plugins +{ + template <typename T> concept isAronGenerated = std::is_base_of<armarx::aron::cpp::AronGeneratedClass, T>::value; + + template <typename AronStructT> + requires isAronGenerated<AronStructT> + class AronComponentConfigPlugin : public ComponentPlugin + { + protected: + void preOnInitComponent() override + { + ManagedIceObjectPlugin::preOnInitComponent(); + } + + void postOnInitComponent() override + { + ManagedIceObjectPlugin::postOnInitComponent(); + } + + void preOnConnectComponent() override + { + armarx::aron::component_config::PropertyDefinitionGetterVisitor vis(parent<armarx::PropertyUser>()); + auto data = std::static_pointer_cast<armarx::aron::data::Variant>(config_.getUpToDateReadBuffer().toAron()); + auto type = config_.getUpToDateReadBuffer().ToAronType(); + armarx::aron::data::visitRecursive(vis, data, type); + config_.getWriteBuffer().fromAron(std::static_pointer_cast<armarx::aron::data::Dict>(data)); + config_.commitWrite(); + + remote_gui_plugin_ + ->createOrUpdateTab(RemoteGui::makeConfigGui("Config", config_.getUpToDateReadBuffer()), + [this](armarx::RemoteGui::TabProxy& prx) + { + ARMARX_TRACE; + prx.receiveUpdates(); + armarx::aron::component_config::GetValueFromMapVisitor vis(&prx); + auto& cfg = config_.getWriteBuffer(); + auto data = std::static_pointer_cast<armarx::aron::data::Variant>(cfg.toAron()); + auto type = cfg.ToAronType(); + armarx::aron::data::visitRecursive(vis, data, type); + cfg.fromAron(std::static_pointer_cast<armarx::aron::data::Dict>(data)); + config_.commitWrite(); + if (vis.tabRebuildRequired()) + { + remote_gui_plugin_->createOrUpdateTab("", RemoteGui::makeConfigGui("Config", config_.getUpToDateReadBuffer())); + } + }); + ManagedIceObjectPlugin::preOnConnectComponent(); + } + + void postOnConnectComponent() override + { + ManagedIceObjectPlugin::postOnConnectComponent(); + } + + void postOnDisconnectComponent() override + { + ManagedIceObjectPlugin::postOnDisconnectComponent(); + } + + void postCreatePropertyDefinitions(armarx::PropertyDefinitionsPtr& properties) override + { + armarx::aron::component_config::PropertyDefinitionSetterVisitor vis(properties); + const auto& config = config_.getUpToDateReadBuffer(); + armarx::aron::data::visitRecursive(vis, config.toAron(), config.ToAronType()); + ComponentPlugin::postCreatePropertyDefinitions(properties); + } + + public: + AronComponentConfigPlugin(ManagedIceObject& parent, const std::string& prefix) : ComponentPlugin(parent, prefix) + { + addPluginAndDependency(remote_gui_plugin_); + } + + armarx::WriteBufferedTripleBuffer<AronStructT> config_; + private: + template <typename PluginT, typename... ParamsT> + void addPluginAndDependency(std::experimental::observer_ptr<PluginT>& plugin, ParamsT&& ...params) + { + PluginT* tmp{nullptr}; + addPlugin(tmp, std::forward<ParamsT>(params)...); + addPluginDependency(tmp); + plugin.reset(tmp); + } + + + std::experimental::observer_ptr<RemoteGuiComponentPlugin> remote_gui_plugin_{nullptr}; + }; +} + +namespace armarx +{ + template <typename AronStructT> + requires plugins::isAronGenerated<AronStructT> + class AronComponentConfigPluginUser : virtual public ManagedIceObject + { + public: + + AronComponentConfigPluginUser() + { + addPlugin(aron_component_config_plugin_, ""); + } + + AronStructT& getConfigWriteBuffer() + { + return aron_component_config_plugin_->config_.getWriteBuffer(); + } + + void commitConfigWriteBuffer() + { + aron_component_config_plugin_->config_.commitWrite(); + } + + const AronStructT& getUpToDateConfigReadBuffer() const + { + return aron_component_config_plugin_->config_.getUpToDateReadBuffer(); + } + + private: + std::experimental::observer_ptr<plugins::AronComponentConfigPlugin<AronStructT>> aron_component_config_plugin_{ + nullptr}; + + }; +} \ No newline at end of file diff --git a/source/RobotAPI/libraries/aron_component_config/PropertyDefinitionVisitors.cpp b/source/RobotAPI/libraries/aron_component_config/PropertyDefinitionVisitors.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a7d1c13a1fb663ff2768b8d33681b198a440b9b5 --- /dev/null +++ b/source/RobotAPI/libraries/aron_component_config/PropertyDefinitionVisitors.cpp @@ -0,0 +1,267 @@ +/* + * This file is part of ArmarX. + * + * ArmarX is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ArmarX is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @package robdekon + * @author Christoph Pohl ( christoph dot pohl at kit dot edu ) + * @date 06.09.22 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + +#include "PropertyDefinitionVisitors.h" + +#include <ArmarXCore/core/application/properties/PropertyDefinitionContainer.h> +#include <ArmarXCore/core/application/properties/PropertyDefinition.h> +#include <ArmarXCore/core/application/properties/PropertyUser.h> +#include <RobotAPI/libraries/aron/core/data/variant/All.h> + +#include "Util.h" + +#define INPUT_GUARD(i) \ +ARMARX_CHECK_NOT_NULL(i); \ +if (in_list_) return; + +namespace armarx::aron::component_config +{ + + void PropertyDefinitionGetterVisitor::visitInt(DataInput& i, TypeInput& elementType) + { + INPUT_GUARD(i); + auto value = data::Int::DynamicCastAndCheck(i); + auto name = pathToName(i); + property_user_->getProperty(value->getValue(), name); + i = value; + } + + void PropertyDefinitionGetterVisitor::visitFloat(DataInput& f, TypeInput& elementType) + { + INPUT_GUARD(f); + auto value = data::Float::DynamicCastAndCheck(f); + auto name = pathToName(f); + property_user_->getProperty(value->getValue(), name); + f = value; + } + + void PropertyDefinitionGetterVisitor::visitDouble(DataInput& d, TypeInput& elementType) + { + INPUT_GUARD(d); + auto value = data::Double::DynamicCastAndCheck(d); + auto name = pathToName(d); + property_user_->getProperty(value->getValue(), name); + d = value; + } + + void PropertyDefinitionGetterVisitor::visitBool(DataInput& b, TypeInput& elementType) + { + INPUT_GUARD(b); + auto value = data::Bool::DynamicCastAndCheck(b); + auto name = pathToName(b); + property_user_->getProperty(value->getValue(), name); + b = value; + } + + void PropertyDefinitionGetterVisitor::visitString(DataInput& string, TypeInput& elementType) + { + INPUT_GUARD(string); + auto value = data::String::DynamicCastAndCheck(string); + auto name = pathToName(string); + property_user_->getProperty(value->getValue(), name); + string = value; + } + + void PropertyDefinitionGetterVisitor::visitListOnEnter(DataInput& o, TypeInput& t) + { + const auto name = pathToName(o); + auto type = type::List::DynamicCast(t); + auto old_list = data::List::DynamicCast(o); + old_list->clear(); + std::string list; + property_user_->getProperty(list, name); + std::vector<std::string> vector = simox::alg::split(list, ","); + int i = 0; + switch (type->getAcceptedType()->getDescriptor()) + { + case type::Descriptor::INT: + { + std::for_each(vector.begin(), vector.end(), [&old_list, &i](const auto& el){ + old_list->addElement(make_int(std::stoi(el), old_list->getPath().withIndex(i))); + i++; + }); + break; + } + case type::Descriptor::STRING: + { + std::for_each(vector.begin(), vector.end(), [&old_list, &i](const auto& el){ + old_list->addElement(make_string(el, old_list->getPath().withIndex(i))); + i++; + }); + break; + } + default: + return; + } + in_list_ = true; + } + + void PropertyDefinitionGetterVisitor::visitListOnExit(DataInput& o, TypeInput& t) + { + in_list_ = false; + } + + void PropertyDefinitionGetterVisitor::visitIntEnum(DataInput& enumData, TypeInput& elementType) + { + auto data = data::Int::DynamicCastAndCheck(enumData); + auto name = pathToName(enumData); + property_user_->getProperty(data->getValue(), name); + enumData = data; + } + + void PropertyDefinitionGetterVisitor::visitUnknown(DataInput& unknown, TypeInput& elementType) + { + ARMARX_WARNING << "Unknown data encountered: " << (unknown ? unknown->getFullName() : "nullptr"); + } + + PropertyDefinitionGetterVisitor::PropertyDefinitionGetterVisitor(const armarx::PropertyUser& defs) : + property_user_(std::experimental::make_observer(&defs)), in_list_(false) + { + + } + + PropertyDefinitionGetterVisitor::MapElements + PropertyDefinitionGetterVisitor::getObjectElements(DataInput& o, TypeInput& t) + { + return component_config::getObjectElements(o, t); + } + + PropertyDefinitionGetterVisitor::MapElements + PropertyDefinitionGetterVisitor::getDictElements(DataInput& o, TypeInput& t) + { + return component_config::getDictElements(o, t); + } + + PropertyDefinitionGetterVisitor::ListElements + PropertyDefinitionGetterVisitor::getListElements(DataInput& o, TypeInput& t) + { + return component_config::getListElements(o, t); + } + + PropertyDefinitionGetterVisitor::PairElements + PropertyDefinitionGetterVisitor::getPairElements(DataInput& o, TypeInput& t) + { + return component_config::getPairElements(o, t); + } + + PropertyDefinitionGetterVisitor::TupleElements + PropertyDefinitionGetterVisitor::getTupleElements(DataInput& o, TypeInput& t) + { + return component_config::getTupleElements(o, t); + } + + type::Descriptor PropertyDefinitionGetterVisitor::getDescriptor(DataInput& o, TypeInput& t) + { + return data::ConstTypedVariantVisitor::GetDescriptor(o, t); + } + + PropertyDefinitionSetterVisitor::PropertyDefinitionSetterVisitor(const PropertyDefinitionsPtr& defs) : + property_definitions_(std::experimental::make_observer(defs.get())) + { + } + + void PropertyDefinitionSetterVisitor::visitAronVariant(const data::IntPtr& i, const type::IntPtr&) + { + INPUT_GUARD(i); + auto name = pathToName(i); + property_definitions_->defineOptionalProperty<int>(name, i->getValue()); + } + + void PropertyDefinitionSetterVisitor::visitAronVariant(const data::FloatPtr& f, const type::FloatPtr&) + { + INPUT_GUARD(f); + auto name = pathToName(f); + property_definitions_->defineOptionalProperty<float>(name, f->getValue()); + } + + void PropertyDefinitionSetterVisitor::visitAronVariant(const data::DoublePtr& d, const type::DoublePtr&) + { + INPUT_GUARD(d); + auto name = pathToName(d); + property_definitions_->defineOptionalProperty<double>(name, d->getValue()); + } + + void PropertyDefinitionSetterVisitor::visitAronVariant(const data::BoolPtr& b, const type::BoolPtr&) + { + INPUT_GUARD(b); + auto name = pathToName(b); + property_definitions_->defineOptionalProperty<bool>(name, b->getValue()); + } + + void PropertyDefinitionSetterVisitor::visitAronVariant(const data::StringPtr& string, const type::StringPtr&) + { + INPUT_GUARD(string); + auto name = pathToName(string); + property_definitions_->defineOptionalProperty<std::string>(name, string->getValue()); + } + + void PropertyDefinitionSetterVisitor::visitAronVariant(const data::IntPtr& i, const type::IntEnumPtr& t) + { + INPUT_GUARD(i); + auto name = pathToName(i); + property_definitions_->defineOptionalProperty<int>(name, i->getValue()).map(t->getAcceptedValueMap()); + } + + void PropertyDefinitionSetterVisitor::visitAronVariantOnEnter(const data::ListPtr& l, const type::ListPtr& t) + { + ARMARX_CHECK_NOT_NULL(l); + in_list_ = true; + auto name = pathToName(l); + auto t_desc = t->getAcceptedType()->getDescriptor(); + auto input = l->getElements(); + std::string str; + switch (t_desc) + { + case type::Descriptor::INT: + { + std::vector<int> vector; + std::transform(input.begin(), input.end(), std::back_inserter(vector), [](const auto& el) + { + return data::Int::DynamicCast(el)->getValue(); + }); + str = simox::alg::to_string(vector, ", "); + break; + } + case type::Descriptor::STRING: + { + std::vector<std::string> vector; + std::transform(input.begin(), input.end(), std::back_inserter(vector), [](const auto& el) + { + return data::String::DynamicCast(el)->getValue(); + }); + str = simox::alg::to_string(vector, ", "); + break; + } + // TODO: other basic types + default: + return; + } + property_definitions_->defineOptionalProperty<std::string>(name, str); + } + + void PropertyDefinitionSetterVisitor::visitAronVariantOnExit(const data::ListPtr&, const type::ListPtr&) + { + in_list_ = false; + } +} + +#undef INPUT_GUARD \ No newline at end of file diff --git a/source/RobotAPI/libraries/aron_component_config/PropertyDefinitionVisitors.h b/source/RobotAPI/libraries/aron_component_config/PropertyDefinitionVisitors.h new file mode 100644 index 0000000000000000000000000000000000000000..34386f5791844ae28ec8e6bf3b6cefac5fca7737 --- /dev/null +++ b/source/RobotAPI/libraries/aron_component_config/PropertyDefinitionVisitors.h @@ -0,0 +1,99 @@ +/* + * This file is part of ArmarX. + * + * ArmarX is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ArmarX is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @package robdekon + * @author Christoph Pohl ( christoph dot pohl at kit dot edu ) + * @date 06.09.22 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + +#pragma once + +#include <experimental/memory> +#include <RobotAPI/libraries/aron/core/data/visitor/variant/VariantVisitor.h> +#include <ArmarXCore/core/application/properties/forward_declarations.h> + +namespace armarx::aron::component_config +{ + + class PropertyDefinitionSetterVisitor : public aron::data::RecursiveConstTypedVariantVisitor + { + public: + explicit PropertyDefinitionSetterVisitor(const armarx::PropertyDefinitionsPtr& defs); + + void visitAronVariant(const data::IntPtr&, const type::IntEnumPtr&) override; + + void visitAronVariant(const data::IntPtr&, const type::IntPtr&) override; + + void visitAronVariant(const data::FloatPtr&, const type::FloatPtr&) override; + + void visitAronVariant(const data::DoublePtr&, const type::DoublePtr&) override; + + void visitAronVariant(const data::BoolPtr&, const type::BoolPtr&) override; + + void visitAronVariant(const data::StringPtr&, const type::StringPtr&) override; + + void visitAronVariantOnEnter(const data::ListPtr&, const type::ListPtr&) override; + + void visitAronVariantOnExit(const data::ListPtr&, const type::ListPtr&) override; + + private: + std::experimental::observer_ptr<PropertyDefinitionContainer> property_definitions_; + std::atomic<bool> in_list_{false}; + }; + + class PropertyDefinitionGetterVisitor : public aron::data::RecursiveTypedVisitor<data::VariantPtr, + const type::VariantPtr> + { + public: + explicit PropertyDefinitionGetterVisitor(const armarx::PropertyUser& defs); + + type::Descriptor getDescriptor(DataInput& o, TypeInput& t) override; + + MapElements getObjectElements(DataInput& o, TypeInput& t) override; + + MapElements getDictElements(DataInput& o, TypeInput& t) override; + + ListElements getListElements(DataInput& o, TypeInput& t) override; + + PairElements getPairElements(DataInput& o, TypeInput& t) override; + + TupleElements getTupleElements(DataInput& o, TypeInput& t) override; + + void visitInt(DataInput& elementData, TypeInput& elementType) override; + + void visitFloat(DataInput& elementData, TypeInput& elementType) override; + + void visitDouble(DataInput& elementData, TypeInput& elementType) override; + + void visitBool(DataInput& elementData, TypeInput& elementType) override; + + void visitString(DataInput& elementData, TypeInput& elementType) override; + + void visitUnknown(DataInput& elementData, TypeInput& elementType) override; + + void visitListOnEnter(DataInput& elementData, TypeInput& elementType) override; + + void visitListOnExit(DataInput& elementData, TypeInput& elementType) override; + + void visitIntEnum(DataInput& elementData, TypeInput& elementType) override; + + private: + std::experimental::observer_ptr<const armarx::PropertyUser> property_user_; + std::atomic<bool> in_list_; + }; + +} \ No newline at end of file diff --git a/source/RobotAPI/libraries/aron_component_config/RemoteGui.h b/source/RobotAPI/libraries/aron_component_config/RemoteGui.h new file mode 100644 index 0000000000000000000000000000000000000000..e790688585294d69d7ff68e39ec54ad763b72046 --- /dev/null +++ b/source/RobotAPI/libraries/aron_component_config/RemoteGui.h @@ -0,0 +1,58 @@ +/* + * This file is part of ArmarX. + * + * ArmarX is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ArmarX is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @package robdekon + * @author Christoph Pohl ( christoph dot pohl at kit dot edu ) + * @date 07.09.22 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + +#pragma once + +#include <ArmarXGui/libraries/RemoteGui/RemoteGui.h> +#include <RobotAPI/libraries/aron/core/data/variant/forward_declarations.h> +#include <RobotAPI/libraries/aron/core/codegeneration/cpp/AronGeneratedClass.h> +#include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h> +#include "RemoteGuiVisitors.h" + +namespace armarx::RemoteGui +{ + template <typename T> concept isAronGenerated = std::is_base_of<armarx::aron::cpp::AronGeneratedClass, T>::value; + + template <typename AronStructT> + requires isAronGenerated<AronStructT> + detail::GroupBoxBuilder makeConfigGui( + const std::string& name, + const AronStructT& val) + { + aron::component_config::MakeConfigGuiVisitor vis(name); + armarx::aron::data::visitRecursive(vis, val.toAron(), val.ToAronType()); + return vis.getGroupBoxBuilder(); + } + +// template <typename AronStructT> +// requires isAronGenerated<AronStructT> +// void getValueFromMap(AronStructT& cfg, +// RemoteGui::ValueMap const& values, std::string const& name) +// { +// armarx::aron::component_config::GetValueFromMapVisitor vis(&values); +// auto data = std::static_pointer_cast<armarx::aron::data::Variant>(cfg.toAron()); +// auto type = cfg.ToAronType(); +// armarx::aron::data::visitRecursive(vis, data, type); +// cfg.fromAron(std::static_pointer_cast<armarx::aron::data::Dict>(data)); +// } + +} \ No newline at end of file diff --git a/source/RobotAPI/libraries/aron_component_config/RemoteGuiVisitors.cpp b/source/RobotAPI/libraries/aron_component_config/RemoteGuiVisitors.cpp new file mode 100644 index 0000000000000000000000000000000000000000..555401357cab15f0a3079f8d2fa84e1fc2c6790c --- /dev/null +++ b/source/RobotAPI/libraries/aron_component_config/RemoteGuiVisitors.cpp @@ -0,0 +1,313 @@ +/* + * This file is part of ArmarX. + * + * ArmarX is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ArmarX is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @package robdekon + * @author Christoph Pohl ( christoph dot pohl at kit dot edu ) + * @date 07.09.22 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + +#include "RemoteGuiVisitors.h" + +#include <ArmarXGui/libraries/RemoteGui/RemoteGui.h> +#include <RobotAPI/libraries/aron/core/data/variant/All.h> +#include <ArmarXCore/util/CPPUtility/Iterator.h> +#include "Util.h" + +#define INPUT_GUARD(i) \ +ARMARX_TRACE; \ +ARMARX_CHECK_NOT_NULL(i); \ +if (in_list_) return; + +namespace armarx::aron::component_config +{ + + void MakeConfigGuiVisitor::visitObjectOnEnter(DataInput& dict, TypeInput&) + { + ARMARX_TRACE; + ARMARX_CHECK_NOT_NULL(dict); + + if (dict->getPath().hasElement()) + { + std::string name = pathToName(dict); + group_hierarchy_ + .emplace_back(std::make_shared<RemoteGui::detail::GroupBoxBuilder>(RemoteGui::makeGroupBox(name))); + } else + { + group_hierarchy_.push_back(builder_); + } + + } + + void MakeConfigGuiVisitor::visitObjectOnExit(DataInput& dict, TypeInput&) + { + ARMARX_TRACE; + auto builder = *group_hierarchy_.back(); + group_hierarchy_.pop_back(); + if (!group_hierarchy_.empty()) + { + group_hierarchy_.back()->addChild(builder); + } + } + + void MakeConfigGuiVisitor::visitInt(DataInput& i, TypeInput&) + { + INPUT_GUARD(i); + auto value = data::Int::DynamicCastAndCheck(i); + group_hierarchy_.back()->addChild( + RemoteGui::makeIntSpinBox(pathToName(i)).value(value->getValue()).min(-1000).max(1000)); + } + + void MakeConfigGuiVisitor::visitFloat(DataInput& f, TypeInput&) + { + INPUT_GUARD(f); + auto value = data::Float::DynamicCastAndCheck(f); + group_hierarchy_.back()->addChild( + RemoteGui::makeFloatSpinBox(pathToName(f)).value(value->getValue()).min(-1000).max(1000)); + } + + void MakeConfigGuiVisitor::visitDouble(DataInput& d, TypeInput&) + { + INPUT_GUARD(d); + auto value = data::Double::DynamicCastAndCheck(d); + group_hierarchy_.back()->addChild( + RemoteGui::makeFloatSpinBox(pathToName(d)).value(value->getValue()).min(-1000).max(1000)); + } + + void MakeConfigGuiVisitor::visitBool(DataInput& b, TypeInput&) + { + INPUT_GUARD(b); + auto value = data::Bool::DynamicCastAndCheck(b); + group_hierarchy_.back()->addChild( + RemoteGui::makeCheckBox(pathToName(b)).value(value->getValue()).label(b->getPath().getLastElement())); + } + + void MakeConfigGuiVisitor::visitString(DataInput& string, TypeInput&) + { + INPUT_GUARD(string); + auto value = data::String::DynamicCastAndCheck(string); + group_hierarchy_.back()->addChild(RemoteGui::makeLineEdit(pathToName(string)).value(value->getValue())); + } + + MakeConfigGuiVisitor::MakeConfigGuiVisitor(const std::string& name) : + builder_(std::make_unique<RemoteGui::detail::GroupBoxBuilder>(name)) + { + } + + RemoteGui::detail::GroupBoxBuilder MakeConfigGuiVisitor::getGroupBoxBuilder() const + { + return *builder_; + } + + void MakeConfigGuiVisitor::visitListOnEnter(DataInput& o, TypeInput& t) + { + auto group = RemoteGui::makeSimpleGridLayout(pathToName(o) + "_grid").cols(20); + auto data = data::List::DynamicCastAndCheck(o); + auto type = type::List::DynamicCast(t); + for (const auto& el: data->getElements()) + { + switch (type->getAcceptedType()->getDescriptor()) + { + case type::Descriptor::STRING: + group.addChild( + RemoteGui::makeLineEdit(pathToName(el)).value(data::String::DynamicCast(el)->getValue()), + 10); + break; + case type::Descriptor::INT: + group.addChild(RemoteGui::makeLineEdit(pathToName(el)) + .value(std::to_string(data::Int::DynamicCast(el)->getValue())), 10); + break; + default: + throw armarx::NotImplementedYetException(); + } + group.addHSpacer(8); + group.addChild(RemoteGui::makeButton(pathToName(el) + "_button").label("-").toolTip("Remove List Element"), + 2); + } + group_hierarchy_.back()->addChild( + RemoteGui::makeGroupBox(pathToName(o) + "_grp").label(o->getPath().getLastElement()).collapsed(true) + .addChild(group).addChild( + RemoteGui::makeButton(pathToName(o) + "_add") + .label("+") + .toolTip("Add new list entry."))); + in_list_ = true; + } + + void MakeConfigGuiVisitor::visitListOnExit(DataInput&, TypeInput&) + { + in_list_ = false; + } + + void MakeConfigGuiVisitor::visitIntEnum(DataInput& o, TypeInput& t) + { + INPUT_GUARD(o); + auto data = data::Int::DynamicCastAndCheck(o); + auto type = type::IntEnum::DynamicCast(t); + group_hierarchy_.back()->addChild(RemoteGui::makeComboBox(pathToName(o)).options(type->getAcceptedValueNames()) + .value(type->getValueName( + data->getValue()))); + } + + + GetValueFromMapVisitor::GetValueFromMapVisitor(armarx::RemoteGui::TabProxy* proxy) : + proxy_(std::experimental::make_observer(proxy)) + { + } + + void GetValueFromMapVisitor::visitInt(DataInput& i, TypeInput&) + { + INPUT_GUARD(i); + auto value = data::Int::DynamicCastAndCheck(i); + proxy_->getValue(value->getValue(), pathToName(i)); + i = value; + } + + void GetValueFromMapVisitor::visitFloat(DataInput& f, TypeInput&) + { + INPUT_GUARD(f); + auto value = data::Float::DynamicCastAndCheck(f); + proxy_->getValue(value->getValue(), pathToName(f)); + f = value; + } + + void GetValueFromMapVisitor::visitDouble(DataInput& d, TypeInput&) + { + INPUT_GUARD(d); + auto value = data::Double::DynamicCastAndCheck(d); + float val_f; + proxy_->getValue(val_f, pathToName(d)); + value->getValue() = val_f; + d = value; + } + + void GetValueFromMapVisitor::visitBool(DataInput& b, TypeInput&) + { + INPUT_GUARD(b); + auto value = data::Bool::DynamicCastAndCheck(b); + proxy_->getValue(value->getValue(), pathToName(b)); + b = value; + } + + void GetValueFromMapVisitor::visitString(DataInput& string, TypeInput&) + { + INPUT_GUARD(string); + auto value = data::String::DynamicCastAndCheck(string); + proxy_->getValue(value->getValue(), pathToName(string)); + string = value; + } + + type::Descriptor GetValueFromMapVisitor::getDescriptor(DataInput& o, TypeInput& t) + { + return data::ConstTypedVariantVisitor::GetDescriptor(o, t); + } + + GetValueFromMapVisitor::MapElements GetValueFromMapVisitor::getObjectElements(DataInput& o, TypeInput& t) + { + return component_config::getObjectElements(o, t); + } + + GetValueFromMapVisitor::MapElements GetValueFromMapVisitor::getDictElements(DataInput& o, TypeInput& t) + { + return component_config::getDictElements(o, t); + } + + GetValueFromMapVisitor::ListElements GetValueFromMapVisitor::getListElements(DataInput& o, TypeInput& t) + { + return component_config::getListElements(o, t); + } + + GetValueFromMapVisitor::PairElements GetValueFromMapVisitor::getPairElements(DataInput& o, TypeInput& t) + { + return component_config::getPairElements(o, t); + } + + GetValueFromMapVisitor::TupleElements GetValueFromMapVisitor::getTupleElements(DataInput& o, TypeInput& t) + { + return component_config::getTupleElements(o, t); + } + + void GetValueFromMapVisitor::visitIntEnum(DataInput& o, TypeInput& t) + { + INPUT_GUARD(o); + auto data = data::Int::DynamicCastAndCheck(o); + auto type = type::IntEnum::DynamicCastAndCheck(t); + std::string str; + proxy_->getValue(str, pathToName(o)); + data->getValue() = type->getValue(str); + o = data; + } + + void GetValueFromMapVisitor::visitListOnEnter(DataInput& o, TypeInput& t) + { + auto data = data::List::DynamicCastAndCheck(o); + auto type = type::List::DynamicCast(t); + const auto& elements = data->getElements(); + for (const auto& [idx, el]: armarx::MakeIndexedContainer(elements)) + { + if (proxy_->getButtonClicked(pathToName(el) + "_button")) + { + data->removeElement(idx); + tab_rebuild_required_ = true; + } + + switch (type->getAcceptedType()->getDescriptor()) + { + case type::Descriptor::STRING: + { + proxy_->getValue(data::String::DynamicCast(el)->getValue(), pathToName(el)); + break; + } + case type::Descriptor::INT: + { + std::string str; + proxy_->getValue(str, pathToName(el)); + data::Int::DynamicCast(el)->getValue() = std::stoi(str); + break; + } + default: + throw armarx::NotImplementedYetException(); + } + } + if (proxy_->getButtonClicked(pathToName(o) + "_add")) + { + switch (type->getAcceptedType()->getDescriptor()) + { + case type::Descriptor::STRING: + data->addElement(make_string("", o->getPath().withIndex(data->childrenSize()))); + break; + case type::Descriptor::INT: + data->addElement(make_int(0, o->getPath().withIndex(data->childrenSize()))); + break; + default: + throw armarx::NotImplementedYetException(); + } + tab_rebuild_required_ = true; + } + in_list_ = true; + } + + void GetValueFromMapVisitor::visitListOnExit(DataInput&, TypeInput&) + { + in_list_ = false; + } + + bool GetValueFromMapVisitor::tabRebuildRequired() const + { + return tab_rebuild_required_; + } +} + +#undef INPUT_GUARD \ No newline at end of file diff --git a/source/RobotAPI/libraries/aron_component_config/RemoteGuiVisitors.h b/source/RobotAPI/libraries/aron_component_config/RemoteGuiVisitors.h new file mode 100644 index 0000000000000000000000000000000000000000..26a201fbd24b07073f7a172cc2a327624da89411 --- /dev/null +++ b/source/RobotAPI/libraries/aron_component_config/RemoteGuiVisitors.h @@ -0,0 +1,120 @@ +/* + * This file is part of ArmarX. + * + * ArmarX is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ArmarX is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @package robdekon + * @author Christoph Pohl ( christoph dot pohl at kit dot edu ) + * @date 07.09.22 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + +#pragma once + +#include <experimental/memory> +#include <RobotAPI/libraries/aron/core/data/visitor/variant/VariantVisitor.h> +#include <ArmarXCore/core/application/properties/forward_declarations.h> + +namespace armarx::RemoteGui +{ + namespace detail + { + class GroupBoxBuilder; + } + class TabProxy; + + class ValueVariant; + + using ValueMap = std::map<std::string, ValueVariant>; +} +namespace armarx::aron::component_config +{ + + class MakeConfigGuiVisitor : public data::RecursiveConstTypedVariantVisitor + { + public: + explicit MakeConfigGuiVisitor(const std::string& name); + + void visitObjectOnEnter(DataInput&, TypeInput&) override; + + void visitObjectOnExit(DataInput&, TypeInput&) override; + + void visitListOnEnter(DataInput&, TypeInput&) override; + + void visitListOnExit(DataInput&, TypeInput&) override; + + + void visitInt(DataInput&, TypeInput&) override; + + void visitIntEnum(DataInput&, TypeInput&) override; + + void visitFloat(DataInput&, TypeInput&) override; + + void visitDouble(DataInput&, TypeInput&) override; + + void visitBool(DataInput&, TypeInput&) override; + + void visitString(DataInput&, TypeInput&) override; + + [[nodiscard]] RemoteGui::detail::GroupBoxBuilder getGroupBoxBuilder() const; + + private: + std::shared_ptr<RemoteGui::detail::GroupBoxBuilder> builder_; + std::vector<std::shared_ptr<RemoteGui::detail::GroupBoxBuilder>> group_hierarchy_; + std::atomic_bool in_list_{false}; + }; + + class GetValueFromMapVisitor : public aron::data::RecursiveTypedVisitor<data::VariantPtr, const type::VariantPtr> + { + public: + explicit GetValueFromMapVisitor(armarx::RemoteGui::TabProxy* proxy); + + type::Descriptor getDescriptor(DataInput&, TypeInput&) override; + + MapElements getObjectElements(DataInput&, TypeInput&) override; + + MapElements getDictElements(DataInput&, TypeInput&) override; + + ListElements getListElements(DataInput&, TypeInput&) override; + + PairElements getPairElements(DataInput&, TypeInput&) override; + + TupleElements getTupleElements(DataInput&, TypeInput&) override; + + void visitListOnEnter(DataInput&, TypeInput&) override; + + void visitListOnExit(DataInput&, TypeInput&) override; + + void visitInt(DataInput&, TypeInput&) override; + + void visitIntEnum(DataInput&, TypeInput&) override; + + void visitFloat(DataInput&, TypeInput&) override; + + void visitDouble(DataInput&, TypeInput&) override; + + void visitBool(DataInput&, TypeInput&) override; + + void visitString(DataInput&, TypeInput&) override; + + bool tabRebuildRequired() const; + + + private: + std::experimental::observer_ptr<armarx::RemoteGui::TabProxy> proxy_; + bool in_list_{false}; + bool tab_rebuild_required_{false}; + }; + +} \ No newline at end of file diff --git a/source/RobotAPI/libraries/aron_component_config/Util.h b/source/RobotAPI/libraries/aron_component_config/Util.h new file mode 100644 index 0000000000000000000000000000000000000000..c6c5561b7112714812896a4eec2269c1f767b597 --- /dev/null +++ b/source/RobotAPI/libraries/aron_component_config/Util.h @@ -0,0 +1,151 @@ +/* + * This file is part of ArmarX. + * + * ArmarX is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ArmarX is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @package robdekon + * @author Christoph Pohl ( christoph dot pohl at kit dot edu ) + * @date 07.09.22 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + +#pragma once + +#include <memory> +#include <numeric> +#include <RobotAPI/libraries/aron/core/data/variant/Variant.h> + + +namespace armarx::aron::component_config +{ + + inline std::string pathToName(const std::shared_ptr<data::Variant>& v) + { + auto vector = v->getPath().getPath(); + auto path = v->getPath(); + path.setDelimeter("."); + path.setRootIdentifier(""); + auto string = path.toString(); + return string.substr(1, string.size()); + } + + template <typename DataInputT, typename TypeInputT> + std::map<std::string, + std::pair<typename std::remove_const<DataInputT>::type, typename std::remove_const<TypeInputT>::type>> + getObjectElements(DataInputT& o, TypeInputT& t) + { + std::map<std::string, std::pair<data::VariantPtr, type::VariantPtr>> ret; + auto x = data::Dict::DynamicCastAndCheck(o); + auto y = type::Object::DynamicCastAndCheck(t); + + ARMARX_CHECK_NOT_NULL(y); + + if (x) + { + for (const auto& [key, e]: x->getElements()) + { + auto ct = y->getMemberType(key); + ret.insert({key, {e, ct}}); + } + } + return ret; + } + + template <typename DataInputT, typename TypeInputT> + std::map<std::string, + std::pair<typename std::remove_const<DataInputT>::type, typename std::remove_const<TypeInputT>::type>> + getDictElements(DataInputT& o, TypeInputT& t) + { + std::map<std::string, std::pair<typename std::remove_const<DataInputT>::type, + typename std::remove_const<TypeInputT>::type>> ret; + auto x = data::Dict::DynamicCastAndCheck(o); + auto y = type::Dict::DynamicCastAndCheck(t); + + auto ac = y ? y->getAcceptedType() : nullptr; + + if (x) + { + for (const auto& [key, e]: x->getElements()) + { + ret.insert({key, {e, ac}}); + } + } + return ret; + } + + template <typename DataInputT, typename TypeInputT> + std::vector<std::pair<typename std::remove_const<DataInputT>::type, typename std::remove_const<TypeInputT>::type>> + getListElements(DataInputT& o, TypeInputT& t) + { + std::vector<std::pair<typename std::remove_const<DataInputT>::type, + typename std::remove_const<TypeInputT>::type>> ret; + auto x = data::List::DynamicCastAndCheck(o); + auto y = type::List::DynamicCastAndCheck(t); + + auto ac = y ? y->getAcceptedType() : nullptr; + + if (x) + { + for (const auto& e: x->getElements()) + { + ret.emplace_back(e, ac); + } + } + return ret; + } + + template <typename DataInputT, typename TypeInputT> + std::pair<std::pair<typename std::remove_const<DataInputT>::type, typename std::remove_const<TypeInputT>::type>, + std::pair<typename std::remove_const<DataInputT>::type, typename std::remove_const<TypeInputT>::type>> + getPairElements(DataInputT& o, TypeInputT& t) + { + auto x = data::List::DynamicCastAndCheck(o); + auto y = type::Pair::DynamicCastAndCheck(t); + + ARMARX_CHECK_NOT_NULL(y); + + if (x) + { + auto e0 = x->getElement(0); + auto ac0 = y->getFirstAcceptedType(); + auto e1 = x->getElement(1); + auto ac1 = y->getSecondAcceptedType(); + return {{e0, ac0}, + {e1, ac1}}; + } + return {}; + } + + template <typename DataInputT, typename TypeInputT> + std::vector<std::pair<typename std::remove_const<DataInputT>::type, typename std::remove_const<TypeInputT>::type>> + getTupleElements(DataInputT& o, TypeInputT& t) + { + std::vector<std::pair<data::VariantPtr, type::VariantPtr>> ret; + auto x = data::List::DynamicCastAndCheck(o); + auto y = type::Tuple::DynamicCastAndCheck(t); + + ARMARX_CHECK_NOT_NULL(y); + + if (x) + { + unsigned int i = 0; + for (const auto& e: x->getElements()) + { + auto ac = y->getAcceptedType(i++); + ret.emplace_back(e, ac); + } + } + return ret; + } +} \ No newline at end of file