// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 #pragma once #include <frantic/max3d/fnpublish/Traits.hpp> #pragma warning( push, 3 ) #include <ifnpub.h> #pragma warning( pop ) namespace frantic { namespace max3d { namespace fnpublish { /** * Object used to declare parameter names and default values. Returned from FPInterfaceDesc<T>::function(). */ class FunctionDesc { public: FunctionDesc( FPFunctionDef* pDesc ); /** * Assigns the name (and optional string table localized description) to the next parameter. * \param szName The name of the parameter. * \param i18nDesc The localized description of the parameter. * \return *this so that you can string multiple param() calls together. */ FunctionDesc& param( const MCHAR* szName, StringResID i18nDesc = 0 ); /** * Marks the parameter as a optional keyword parameter and assigns the name and default value. Throws * std::logic_error if the default value is not the correct type. * * \note All following parameters must be optional keyword parameters or a std::logic_error is thrown. * * \param szName The name of the parameter. * \param defaultValue The default value if this keyword parameter is not supplied. * \param i18nDesc The localized description of the parameter. * \return *this so that you can string multiple param() calls together. */ template <class T> FunctionDesc& param( const MCHAR* szName, const T& defaultValue, StringResID i18nDesc = 0 ); private: FPParamDef* get_param( std::size_t i ); private: FPFunctionDef* m_pDesc; std::size_t m_counter; }; /** * Object used to declare the options of an enumeration, and the associated name used in MAXScript */ template <class EnumType> class EnumDesc { public: EnumDesc( FPEnum* pDesc ); /** * Adds a new option to the enumeration with the given name and value * \param szName The name of the option. * \param value The value of the enumeration option. */ EnumDesc& option( const MCHAR* szName, EnumType value ); private: FPEnum* m_pDesc; }; inline FunctionDesc::FunctionDesc( FPFunctionDef* pDesc ) : m_pDesc( pDesc ) , m_counter( 0 ) {} inline FPParamDef* FunctionDesc::get_param( std::size_t i ) { if( i < static_cast<std::size_t>( m_pDesc->params.Count() ) ) return m_pDesc->params[static_cast<int>( i )]; throw std::out_of_range( "Invalid parameter index" ); } inline FunctionDesc& FunctionDesc::param( const MCHAR* szName, StringResID i18nDesc ) { FPParamDef* pParam = this->get_param( m_counter++ ); if( m_pDesc->flags & FP_HAS_KEYARGS ) throw std::logic_error( "Invalid positional argument after keyword argument" ); pParam->internal_name = const_cast<MCHAR*>( szName ); // Max 2010 expects a non-const static char* pParam->description = i18nDesc; return *this; } namespace detail { template <class T> struct ArrayToPtr { typedef T type; }; template <class T, int N> struct ArrayToPtr<T[N]> { typedef T* type; }; } // namespace detail template <class T> inline FunctionDesc& FunctionDesc::param( const MCHAR* szName, const T& defaultValue, StringResID i18nDesc ) { FPParamDef* pParam = this->get_param( m_counter++ ); // Passing a string constant was mucking things up due to its type being 'const char[N]' instead of 'const char*', // so I fix that here. #if MAX_VERSION_MAJOR < 19 typedef typename detail::ArrayToPtr<T>::type TModified; if( Traits<typename RemoveConstRef<TModified>::type>::fp_param_type() != pParam->type ) #else // There were some breaking changes to template specialization in Visual Studio 2015. // This caused the old code for dealing with string literals to fail to find the corret Traits<> specialization. // This explicitly deals with them. typedef typename std::remove_extent<T>::type noextent_t; typedef typename std::conditional<std::is_same<MCHAR, noextent_t>::value, const MCHAR*, T>::type fixedstr_t; if( Traits<fixedstr_t>::fp_param_type() != pParam->type ) #endif throw std::logic_error( "Invalid default parameter value type" ); m_pDesc->flags |= FP_HAS_KEYARGS; m_pDesc->keyparam_count++; pParam->internal_name = const_cast<MCHAR*>( szName ); // Max 2010 expects a non-const static char* pParam->description = i18nDesc; pParam->flags |= FPP_KEYARG; if( !pParam->options ) pParam->options = new FPParamOptions; #if MAX_VERSION_MAJOR < 19 Traits<typename RemoveConstRef<TModified>::type>::get_return_value( pParam->options->keyarg_default, defaultValue ); #else Traits<fixedstr_t>::get_return_value( pParam->options->keyarg_default, defaultValue ); #endif return *this; } template <class EnumType> inline EnumDesc<EnumType>::EnumDesc( FPEnum* pDesc ) : m_pDesc( pDesc ) {} template <class EnumType> inline EnumDesc<EnumType>& EnumDesc<EnumType>::option( const MCHAR* szName, EnumType value ) { FPEnum::enum_code newCode; newCode.name = const_cast<MCHAR*>( szName ); // Max 2010 expects a non-const static char* newCode.code = static_cast<int>( value ); m_pDesc->enumeration.Append( 1, &newCode ); return *this; } } // namespace fnpublish } // namespace max3d } // namespace frantic