QML registration using templates instead of macros. lower/uppercase

definitions for gadgets solved ( defining then twice to have the enums
with uppercase prefix )
This commit is contained in:
Uwe Rathmann 2022-11-20 15:36:30 +01:00
parent 2aaaa4ecb1
commit ea8f426d67
2 changed files with 139 additions and 138 deletions

View File

@ -53,116 +53,128 @@
#include <qqmlengine.h>
#endif
#if QT_VERSION < QT_VERSION_CHECK( 6, 2, 0 )
QSK_QT_PRIVATE_BEGIN
#include <private/qqmlmetatype_p.h>
QSK_QT_PRIVATE_END
#endif
#include <ctype.h>
#define QSK_MODULE_NAME "Skinny"
#define QSK_VERSION_MAJOR 1
#define QSK_VERSION_MINOR 0
#define QSK_REGISTER( className, typeName ) \
registerType< className >( typeName );
#define QSK_REGISTER_GADGET( className, typeName ) \
registerGadget< className >( typeName )
#define QSK_REGISTER_NAMESPACE( className, typeName ) \
registerStaticMetaObject( className::staticMetaObject, typeName )
#define QSK_REGISTER_SINGLETON( className, typeName, singleton ) \
registerSingleton< className >( typeName, singleton );
// Required for QFlags to be constructed from an enum value
#define QSK_REGISTER_FLAGS( Type ) \
QMetaType::registerConverter< int, Type >([] ( int value ) { return Type( value ); })
QMetaType::registerConverter< int, Type >( []( int value ) { return Type( value ); } )
namespace
{
template < typename T >
inline int registerType( const char *qmlName )
inline const char* classNameQml( const QMetaObject& metaObject )
{
return qmlRegisterType< T >( QSK_MODULE_NAME,
QSK_VERSION_MAJOR, QSK_VERSION_MINOR, qmlName );
// without the "Qsk" prefix
return metaObject.className() + 3;
}
template < typename T >
inline int registerGadget( const char *qmlName )
/*
There are several undocumented methods for QML registrations in qqml.h
f.e qmlRegisterCustomType, where you can pass your own parser. TODO ..
*/
template< typename T >
inline int registerType( const char* qmlName )
{
return qmlRegisterUncreatableType< T >( QSK_MODULE_NAME,
QSK_VERSION_MAJOR, QSK_VERSION_MINOR, qmlName, QString() );
return qmlRegisterType< T >(
QSK_MODULE_NAME, QSK_VERSION_MAJOR, QSK_VERSION_MINOR,
qmlName );
}
inline int registerStaticMetaObject( const QMetaObject &metaObject, const char *qmlName )
template< typename T >
inline int registerUncreatableType( const char* qmlName )
{
return qmlRegisterUncreatableMetaObject( metaObject, QSK_MODULE_NAME,
QSK_VERSION_MAJOR, QSK_VERSION_MINOR, qmlName, QString() );
return qmlRegisterUncreatableType< T >(
QSK_MODULE_NAME, QSK_VERSION_MAJOR, QSK_VERSION_MINOR,
qmlName, QString() );
}
int registerUncreatableMetaObject(
const QMetaObject& staticMetaObject, const char* qmlName )
{
return qmlRegisterUncreatableMetaObject(
staticMetaObject,
QSK_MODULE_NAME, QSK_VERSION_MAJOR, QSK_VERSION_MINOR,
qmlName, QString() );
}
template< typename T >
inline void registerObject( const char* qmlName = nullptr )
{
// the class name without the "Qsk" prefix
if ( qmlName == nullptr )
qmlName = classNameQml( T::staticMetaObject );
( void ) registerType< T >( qmlName );
}
template< typename T >
inline void registerGadget()
{
auto className = classNameQml( T::staticMetaObject );
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
registerUncreatableType< T >( className );
#else
// the class name without the "Qsk" prefix
/*
According to the QML naming rules uncreatables have to
start with a lowercase letter ( since Qt6 ) , while namespaces
and creatable items usually start with a upper letter.
This results in an odd naming scheme for the enums defined inside of gadgets.
To work around this we register the gadget twice - starting with
upper or lower letter.
Maybe it would make sense to only pass stripped metaObjects, where all
enums are removed from the first and everything else than the enums from
the second. TODO ...
*/
registerUncreatableMetaObject( T::staticMetaObject, className );
QByteArray name = className;
name.data()[0] = std::tolower( name.data()[0] );
registerUncreatableType< T >( name.constData() );
#endif
}
inline int registerNamespace( const QMetaObject& metaObject )
{
return registerUncreatableMetaObject( metaObject, classNameQml( metaObject ) );
}
template< typename T >
inline int registerSingleton( QObject* singleton )
{
const auto name = classNameQml( T::staticMetaObject );
#if QT_VERSION < QT_VERSION_CHECK( 5, 14, 0 )
template < typename T >
inline int registerSingleton( const char *typeName, QObject* singleton )
{
auto callback =
[] ( QQmlEngine*, QJSEngine* )
[]( QQmlEngine*, QJSEngine* )
{
QQmlEngine::setObjectOwnership( singleton, QQmlEngine::CppOwnership );
return singleton;
};
return qmlRegisterSingletonType< T >( QSK_MODULE_NAME,
QSK_VERSION_MAJOR, QSK_VERSION_MINOR, typeName, callback );
}
QSK_VERSION_MAJOR, QSK_VERSION_MINOR, name, callback );
#else
template < typename T >
inline int registerSingleton( const char *typeName, QObject* singleton )
{
return qmlRegisterSingletonInstance( QSK_MODULE_NAME,
QSK_VERSION_MAJOR, QSK_VERSION_MINOR, typeName, singleton );
QSK_VERSION_MAJOR, QSK_VERSION_MINOR, name, singleton );
#endif
}
#endif
}
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
#include <qloggingcategory.h>
namespace
{
class WarningBlocker
{
public:
WarningBlocker()
{
m_oldFilter = QLoggingCategory::installFilter( &WarningBlocker::filter );
}
~WarningBlocker()
{
QLoggingCategory::installFilter( m_oldFilter );
}
private:
static void filter( QLoggingCategory* category )
{
if ( qstrcmp( category->categoryName(), "qt.qml.typeregistration" ) == 0 )
{
category->setEnabled( QtWarningMsg, false);
return;
}
m_oldFilter(category);
}
static QLoggingCategory::CategoryFilter m_oldFilter;
};
QLoggingCategory::CategoryFilter WarningBlocker::m_oldFilter;
}
#endif
static inline QskGradientStop qskJSToGradientStop( const QJSValue& value )
{
return QskGradientStop(
@ -183,44 +195,47 @@ void QskQml::registerTypes()
qmlRegisterUncreatableType< QskSkin >( QSK_MODULE_NAME, 1, 0, "Skin", QString() );
qRegisterMetaType< QskSkin* >();
QSK_REGISTER( QskMain, "Main" );
QSK_REGISTER( QskShortcutQml, "Shortcut" );
registerObject< QskMain >();
registerObject< QskShortcutQml >( "Shortcut" );
QSK_REGISTER( QskWindow, "Window" );
registerObject< QskWindow >();
QSK_REGISTER( QskDialogWindow, "DialogWindow" );
QSK_REGISTER( QskMessageWindow, "MessageWindow" );
QSK_REGISTER( QskSelectionWindow, "SelectionWindow" );
registerObject< QskDialogWindow >();
registerObject< QskMessageWindow >();
registerObject< QskSelectionWindow >();
QSK_REGISTER( QskGridBoxQml, "GridBox" );
QSK_REGISTER( QskLinearBoxQml, "LinearBox" );
registerObject< QskGridBoxQml >( "GridBox" );
registerObject< QskLinearBoxQml >( "LinearBox" );
QSK_REGISTER( QskControl, "Control" );
QSK_REGISTER( QskGraphicLabel, "GraphicLabel" );
QSK_REGISTER( QskVirtualKeyboard, "VirtualKeyboard" );
QSK_REGISTER( QskTextLabel, "TextLabel" );
QSK_REGISTER( QskTabButton, "TabButton" );
QSK_REGISTER( QskTabBar, "TabBar" );
QSK_REGISTER( QskTabView, "TabView" );
QSK_REGISTER( QskFocusIndicator, "FocusIndicator" );
QSK_REGISTER( QskSeparator, "Separator" );
QSK_REGISTER( QskProgressBar, "ProgressBar" );
QSK_REGISTER( QskPushButton, "PushButton" );
QSK_REGISTER( QskScrollView, "ScrollView" );
QSK_REGISTER( QskScrollArea, "ScrollArea" );
QSK_REGISTER( QskSlider, "Slider" );
QSK_REGISTER( QskSimpleListBox, "SimpleListBox" );
QSK_REGISTER( QskDialogButton, "DialogButton" );
QSK_REGISTER( QskDialogButtonBox, "DialogButtonBox" );
QSK_REGISTER( QskPopup, "Popup" );
QSK_REGISTER( QskStatusIndicator, "StatusIndicator" );
QSK_REGISTER( QskSubWindow, "SubWindow" );
QSK_REGISTER( QskSubWindowArea, "SubWindowArea" );
QSK_REGISTER( QskDialogSubWindow, "DialogSubWindow" );
registerObject< QskControl >();
registerObject< QskGraphicLabel >();
registerObject< QskVirtualKeyboard >();
registerObject< QskTextLabel >();
registerObject< QskTabButton >();
registerObject< QskTabBar >();
registerObject< QskTabView >();
registerObject< QskFocusIndicator >();
registerObject< QskSeparator >();
registerObject< QskProgressBar >();
registerObject< QskPushButton >();
registerObject< QskScrollView >();
registerObject< QskScrollArea >();
registerObject< QskSlider >();
registerObject< QskSimpleListBox >();
registerObject< QskDialogButton >();
registerObject< QskDialogButtonBox >();
registerObject< QskPopup >();
registerObject< QskStatusIndicator >();
registerObject< QskSubWindow >();
registerObject< QskSubWindowArea >();
registerObject< QskDialogSubWindow >();
QSK_REGISTER_SINGLETON( QskDialog, "Dialog", QskDialog::instance() );
registerSingleton< QskDialog >( QskDialog::instance() );
qmlRegisterUncreatableType< QskSkin >( "Skinny.Skins", 1, 0, "Skin", QString() );
#if 0
qmlRegisterUncreatableType< QskSkin >( "Skinny.Skins",
QSK_VERSION_MAJOR, QSK_VERSION_MINOR, "Skin", QString() );
#endif
QSK_REGISTER_FLAGS( QskQuickItem::UpdateFlag );
QSK_REGISTER_FLAGS( QskQuickItem::UpdateFlags );
@ -228,37 +243,21 @@ void QskQml::registerTypes()
QSK_REGISTER_FLAGS( QskDialog::Actions );
{
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
/*
The QML engine warns about registering uncreatables with names starting with
a capital letter. But as those classes usually appear only as scope for
local enums in QML, we do want to have capitals. f.e.:
registerGadget< QskBoxBorderMetrics >();
registerGadget< QskBoxShapeMetrics >();
registerGadget< QskShadowMetrics >();
registerGadget< QskIntervalF >();
registerGadget< QskLayoutMetrics >();
registerGadget< QskMargins >();
- "policy.horizonalPolicy : SizePolicy::Minimum".
registerGadget< QskAspect >();
registerGadget< QskGradient >();
registerGadget< QskGradientStop >();
registerGadget< QskPlacementPolicy >();
registerGadget< QskSizePolicy >();
registerGadget< QskTextOptions >();
Maybe we need to introduce some dummy gadgets exposing the enums
in capital letters by using QML_FOREIGN_NAMESPACE, while the
original gadget is exposed in lower letters. TODO ...
*/
WarningBlocker warningBlocker;
#endif
QSK_REGISTER_GADGET( QskBoxBorderMetrics, "BorderMetrics" );
QSK_REGISTER_GADGET( QskBoxShapeMetrics, "Shape" );
QSK_REGISTER_GADGET( QskShadowMetrics, "ShadowMetrics" );
QSK_REGISTER_GADGET( QskGradient, "Gradient" );
QSK_REGISTER_GADGET( QskGradientStop, "GradientStop" );
QSK_REGISTER_GADGET( QskPlacementPolicy, "PlacementPolicy" );
QSK_REGISTER_GADGET( QskIntervalF, "IntervalF" );
QSK_REGISTER_GADGET( QskLayoutMetrics, "LayoutMetrics" );
QSK_REGISTER_GADGET( QskSizePolicy, "SizePolicy" );
QSK_REGISTER_GADGET( QskTextOptions, "TextOptions" );
QSK_REGISTER_GADGET( QskMargins, "Margins" );
QSK_REGISTER_GADGET( QskAspect, "Aspect" );
}
QSK_REGISTER_NAMESPACE( QskStandardSymbol, "StandardSymbol" );
registerNamespace( QskStandardSymbol::staticMetaObject );
QMetaType::registerConverter< QJSValue, QskGradientStop >( qskJSToGradientStop );

View File

@ -142,8 +142,10 @@ class QSK_EXPORT QskGradient
Couldn't find a way how to assign a struct to another struct
that is used as proprty from QML without creating extra QObjects.
So for the moment we are using lists, that are more
error prone and less intuitive. Let's see if some day we will have
the QML system being capable of this. TODO ...
error prone and less intuitive.
Maybe we can do something better using qmlRegisterCustomType, where we
can register our own QQmlCustomParser. TODO ...
*/
Q_PROPERTY( QVector< qreal > linear READ linearAsList WRITE setLinearAsList )
Q_PROPERTY( QVector< qreal > conic READ conicAsList WRITE setConicAsList )