QJSValue converter for QskGradient added to be compatible with new Qt
6.5 features
This commit is contained in:
parent
57c25294c4
commit
abf325dbde
@ -7,15 +7,15 @@ GridBox
|
|||||||
//margins: 10 // only possible with Qt <= 6.1 || Qt >= 6.5
|
//margins: 10 // only possible with Qt <= 6.1 || Qt >= 6.5
|
||||||
margins { left: 10; top: 10; right: 10; bottom: 10 }
|
margins { left: 10; top: 10; right: 10; bottom: 10 }
|
||||||
|
|
||||||
background
|
background:
|
||||||
{
|
({
|
||||||
linear: [ 0.0, 0.0, 1.0, 0.0 ]
|
linear: { x1: 0, y1: 0, x2: 1, y2: 1 }, // diagonal
|
||||||
|
|
||||||
stops: [
|
stops: [
|
||||||
{ position: 0.0, color: "Red" },
|
{ position: 0.0, color: "Red" },
|
||||||
{ position: 1.0, color: "Yellow" },
|
{ position: 1.0, color: "Yellow" }
|
||||||
]
|
]
|
||||||
}
|
})
|
||||||
|
|
||||||
TestRectangle
|
TestRectangle
|
||||||
{
|
{
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
#include "QskQml.h"
|
#include "QskQml.h"
|
||||||
|
#include "QskQml.hpp"
|
||||||
|
|
||||||
#include "QskLayoutQml.h"
|
#include "QskLayoutQml.h"
|
||||||
#include "QskShortcutQml.h"
|
#include "QskShortcutQml.h"
|
||||||
#include "QskMainQml.h"
|
#include "QskMainQml.h"
|
||||||
@ -50,301 +52,121 @@
|
|||||||
#include <QskVirtualKeyboard.h>
|
#include <QskVirtualKeyboard.h>
|
||||||
#include <QskWindow.h>
|
#include <QskWindow.h>
|
||||||
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK( 5, 14, 0 )
|
|
||||||
#include <qqmlengine.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK( 6, 2, 0 )
|
#if QT_VERSION < QT_VERSION_CHECK( 6, 2, 0 )
|
||||||
QSK_QT_PRIVATE_BEGIN
|
QSK_QT_PRIVATE_BEGIN
|
||||||
#include <private/qqmlmetatype_p.h>
|
#include <private/qqmlmetatype_p.h>
|
||||||
QSK_QT_PRIVATE_END
|
QSK_QT_PRIVATE_END
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <ctype.h>
|
#if QT_VERSION < QT_VERSION_CHECK( 6, 5, 0 )
|
||||||
|
|
||||||
#define QSK_MODULE_NAME "Skinny"
|
#include <qjsvalue.h>
|
||||||
#define QSK_VERSION_MAJOR 1
|
#include <qjsvalueiterator.h>
|
||||||
#define QSK_VERSION_MINOR 0
|
|
||||||
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK( 6, 3, 0 )
|
|
||||||
#define QSK_STRUCT_VERSION 0
|
|
||||||
#elif QT_VERSION < QT_VERSION_CHECK( 6, 5, 0 )
|
|
||||||
#define QSK_STRUCT_VERSION 1
|
|
||||||
#else
|
|
||||||
#define QSK_STRUCT_VERSION 2
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Required for QFlags to be constructed from an enum value
|
|
||||||
#define QSK_REGISTER_FLAGS( Type ) \
|
|
||||||
QMetaType::registerConverter< int, Type >( []( int value ) { return Type( value ); } )
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
inline const char* classNameQml( const QMetaObject& metaObject )
|
|
||||||
{
|
|
||||||
// without the "Qsk" prefix
|
|
||||||
return metaObject.className() + 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
ClassInfo corresponds to the most reecent QQmlPrivate::RegisterType
|
Since Qt 6.5 we have QML_STRUCTURED_VALUE and do not need to
|
||||||
( structVersion: 2 introduced with Qt 6.5 )
|
write our own converter.
|
||||||
|
|
||||||
|
However: we should also be able to implement a generic converter from the
|
||||||
|
metatype information: TODO ...
|
||||||
|
|
||||||
|
For the moment we have these converters:
|
||||||
*/
|
*/
|
||||||
class ClassInfo
|
QskGradientStop toGradientStop( const QJSValue& value )
|
||||||
{
|
{
|
||||||
public:
|
return QskGradientStop(
|
||||||
|
value.property( QStringLiteral( "position" ) ).toNumber(),
|
||||||
|
value.property( QStringLiteral( "color" ) ).toVariant().value< QColor >()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
template< typename T >
|
QskLinearDirection toLinearDirection( const QJSValue& value )
|
||||||
void setTypeInfo()
|
{
|
||||||
|
return QskLinearDirection(
|
||||||
|
value.property( QStringLiteral( "x1" ) ).toNumber(),
|
||||||
|
value.property( QStringLiteral( "y1" ) ).toNumber(),
|
||||||
|
value.property( QStringLiteral( "x2" ) ).toNumber(),
|
||||||
|
value.property( QStringLiteral( "y2" ) ).toNumber() );
|
||||||
|
}
|
||||||
|
|
||||||
|
QskConicDirection toConicDirection( const QJSValue& value )
|
||||||
|
{
|
||||||
|
return QskConicDirection(
|
||||||
|
value.property( QStringLiteral( "x" ) ).toNumber(),
|
||||||
|
value.property( QStringLiteral( "y" ) ).toNumber(),
|
||||||
|
value.property( QStringLiteral( "startAngle" ) ).toNumber(),
|
||||||
|
value.property( QStringLiteral( "spanAngle" ) ).toNumber() );
|
||||||
|
}
|
||||||
|
|
||||||
|
QskRadialDirection toRadialDirection( const QJSValue& value )
|
||||||
|
{
|
||||||
|
return QskRadialDirection(
|
||||||
|
value.property( QStringLiteral( "x" ) ).toNumber(),
|
||||||
|
value.property( QStringLiteral( "y" ) ).toNumber(),
|
||||||
|
value.property( QStringLiteral( "radius" ) ).toNumber() );
|
||||||
|
}
|
||||||
|
|
||||||
|
QskGradient toGradient( const QJSValue& value )
|
||||||
|
{
|
||||||
|
QskGradient gradient;
|
||||||
|
|
||||||
|
QJSValueIterator it( value );
|
||||||
|
|
||||||
|
while ( it.hasNext() )
|
||||||
{
|
{
|
||||||
using namespace QQmlPrivate;
|
it.next();
|
||||||
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
|
auto v = it.value();
|
||||||
const char* className = T::staticMetaObject.className(); \
|
|
||||||
|
|
||||||
const int nameLen = int(strlen(className) ); \
|
if ( v.isObject() )
|
||||||
const int listLen = int(strlen("QQmlListProperty<") ); \
|
|
||||||
|
|
||||||
QVarLengthArray< char,64 > listName(listLen + nameLen + 2); \
|
|
||||||
memcpy(listName.data(), "QQmlListProperty<", size_t(listLen) ); \
|
|
||||||
memcpy(listName.data() + listLen, className, size_t(nameLen) ); \
|
|
||||||
listName[listLen + nameLen] = '>'; \
|
|
||||||
listName[listLen + nameLen + 1] = '\0';
|
|
||||||
|
|
||||||
typeId = qMetaTypeId< T* >( );
|
|
||||||
listId = qRegisterNormalizedMetaType< QQmlListProperty< T > >( listName.constData() );
|
|
||||||
#else
|
|
||||||
if constexpr (std::is_base_of_v< QObject, T >)
|
|
||||||
{
|
{
|
||||||
typeId = QMetaType::fromType< T* >( );
|
if ( v.isArray() )
|
||||||
listId = QMetaType::fromType< QQmlListProperty< T > >( );
|
{
|
||||||
|
if ( it.name() == QStringLiteral( "stops" ) )
|
||||||
|
{
|
||||||
|
QskGradientStops stops;
|
||||||
|
|
||||||
|
const int n = v.property( QStringLiteral( "length" ) ).toInt();
|
||||||
|
for ( int i = 0; i < n; i++ )
|
||||||
|
stops += toGradientStop( v.property( i ) );
|
||||||
|
|
||||||
|
gradient.setStops( stops );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( it.name() == QStringLiteral( "linear" ) )
|
||||||
|
{
|
||||||
|
gradient.setLinearDirection( toLinearDirection( v ) );
|
||||||
|
}
|
||||||
|
else if ( it.name() == QStringLiteral( "conic" ) )
|
||||||
|
{
|
||||||
|
gradient.setConicDirection( toConicDirection( v ) );
|
||||||
|
}
|
||||||
|
else if ( it.name() == QStringLiteral( "radial" ) )
|
||||||
|
{
|
||||||
|
gradient.setRadialDirection( toRadialDirection( v ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
typeId = QMetaType::fromType< T >( );
|
|
||||||
listId = QMetaType::fromType< QList< T > >( );
|
|
||||||
}
|
|
||||||
|
|
||||||
createValueType = ValueType< T, void >::create;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
parserStatusCast = StaticCastSelector< T,QQmlParserStatus >::cast();
|
|
||||||
valueSourceCast = StaticCastSelector< T,QQmlPropertyValueSource >::cast();
|
|
||||||
valueInterceptorCast = StaticCastSelector< T,QQmlPropertyValueInterceptor >::cast();
|
|
||||||
#if QSK_STRUCT_VERSION >= 1
|
|
||||||
finalizerCast = StaticCastSelector< T,QQmlFinalizerHook >::cast();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
return gradient;
|
||||||
const int structVersion = QSK_STRUCT_VERSION;
|
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
|
|
||||||
QMetaType typeId;
|
|
||||||
QMetaType listId;
|
|
||||||
#else
|
|
||||||
int typeId = 0;
|
|
||||||
int listId = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int objectSize = 0;
|
|
||||||
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
|
|
||||||
void ( *create )( void* ) = nullptr;
|
|
||||||
#else
|
|
||||||
void ( *create )( void*, void* ) = nullptr;
|
|
||||||
void* const userdata = nullptr; // unused
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const QString noCreationReason; // unused
|
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
|
|
||||||
/*
|
|
||||||
This one was introdued with Qt 6.x, but never worked
|
|
||||||
as expected. With Qt 6.5 it has been replaced by adding
|
|
||||||
the creationMethod that is triggering to look for
|
|
||||||
invokable constructors.
|
|
||||||
Let's check if it makes any sense to initialize it below
|
|
||||||
at all. TODO ...
|
|
||||||
*/
|
|
||||||
QVariant ( *createValueType )( const QJSValue& ) = nullptr;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const char* const uri = QSK_MODULE_NAME;
|
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
|
|
||||||
const QTypeRevision version =
|
|
||||||
QTypeRevision::fromVersion( QSK_VERSION_MAJOR, QSK_VERSION_MINOR );
|
|
||||||
#else
|
|
||||||
const int versionMajor = QSK_VERSION_MAJOR;
|
|
||||||
const int versionMinor = QSK_VERSION_MINOR;
|
|
||||||
#endif
|
|
||||||
const char* elementName = nullptr;
|
|
||||||
const QMetaObject* metaObject = nullptr;
|
|
||||||
|
|
||||||
/*
|
|
||||||
We do not use attached properties as it always comes with
|
|
||||||
creating extra QObjects.
|
|
||||||
*/
|
|
||||||
QObject* (* const attachedPropertiesFunction)( QObject* ) = nullptr;
|
|
||||||
const QMetaObject* const attachedPropertiesMetaObject = nullptr;
|
|
||||||
|
|
||||||
int parserStatusCast = -1;
|
|
||||||
int valueSourceCast = -1;
|
|
||||||
int valueInterceptorCast = -1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
We do not use extensions as it always comes with
|
|
||||||
creating extra QObjects.
|
|
||||||
*/
|
|
||||||
QObject* (* const extensionObjectCreate )( QObject* ) = nullptr;
|
|
||||||
const QMetaObject* const extensionMetaObject = nullptr;
|
|
||||||
|
|
||||||
QQmlCustomParser* const customParser = nullptr; // unused
|
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
|
|
||||||
const QTypeRevision revision = QTypeRevision::zero();
|
|
||||||
#else
|
|
||||||
const int revision = 0;
|
|
||||||
#endif
|
|
||||||
int finalizerCast = -1;
|
|
||||||
|
|
||||||
const int creationMethod = 2; // ValueTypeCreationMethod::Structured
|
|
||||||
};
|
|
||||||
|
|
||||||
template< typename T >
|
|
||||||
inline int registerType( const char* qmlName )
|
|
||||||
{
|
|
||||||
using namespace QQmlPrivate;
|
|
||||||
|
|
||||||
ClassInfo type;
|
|
||||||
|
|
||||||
type.setTypeInfo< T >();
|
|
||||||
|
|
||||||
type.objectSize = sizeof( T );
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
|
|
||||||
type.create = Constructors< T >::createInto;
|
|
||||||
#else
|
|
||||||
type.create = createInto< T >;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
type.elementName = qmlName;
|
|
||||||
type.metaObject = & T::staticMetaObject;
|
|
||||||
|
|
||||||
return qmlregister( TypeRegistration, & type );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template< typename T >
|
void registerJSConverters()
|
||||||
inline int registerUncreatableType( const char* qmlName )
|
|
||||||
{
|
{
|
||||||
using namespace QQmlPrivate;
|
QMetaType::registerConverter< QJSValue, QskGradient >( toGradient );
|
||||||
|
QMetaType::registerConverter< QJSValue, QskLinearDirection >( toLinearDirection );
|
||||||
ClassInfo type;
|
QMetaType::registerConverter< QJSValue, QskConicDirection >( toConicDirection );
|
||||||
|
QMetaType::registerConverter< QJSValue, QskRadialDirection >( toRadialDirection );
|
||||||
type.setTypeInfo< T >( );
|
QMetaType::registerConverter< QJSValue, QskGradientStop >( toGradientStop );
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
|
|
||||||
type.objectSize = sizeof( T );
|
|
||||||
type.create = Constructors< T >::createInto;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
type.elementName = qmlName;
|
|
||||||
type.metaObject = & T::staticMetaObject;
|
|
||||||
|
|
||||||
return qmlregister( TypeRegistration, & type );
|
|
||||||
}
|
|
||||||
|
|
||||||
int registerUncreatableMetaObject(
|
|
||||||
const QMetaObject& staticMetaObject, const char* qmlName )
|
|
||||||
{
|
|
||||||
using namespace QQmlPrivate;
|
|
||||||
|
|
||||||
ClassInfo type;
|
|
||||||
|
|
||||||
type.elementName = qmlName;
|
|
||||||
type.metaObject = & staticMetaObject;
|
|
||||||
|
|
||||||
return qmlregister( TypeRegistration, & type );
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
/*
|
|
||||||
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 ...
|
|
||||||
*/
|
|
||||||
|
|
||||||
if ( T::staticMetaObject.enumeratorCount() > 0 )
|
|
||||||
{
|
|
||||||
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 )
|
|
||||||
auto callback =
|
|
||||||
[]( QQmlEngine*, QJSEngine* )
|
|
||||||
{
|
|
||||||
QQmlEngine::setObjectOwnership( singleton, QQmlEngine::CppOwnership );
|
|
||||||
return singleton;
|
|
||||||
};
|
|
||||||
|
|
||||||
return qmlRegisterSingletonType< T >( QSK_MODULE_NAME,
|
|
||||||
QSK_VERSION_MAJOR, QSK_VERSION_MINOR, name, callback );
|
|
||||||
#else
|
|
||||||
return qmlRegisterSingletonInstance( QSK_MODULE_NAME,
|
|
||||||
QSK_VERSION_MAJOR, QSK_VERSION_MINOR, name, singleton );
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline QskGradientStop qskJSToGradientStop( const QJSValue& value )
|
#endif
|
||||||
{
|
|
||||||
return QskGradientStop(
|
|
||||||
value.property( QStringLiteral( "position" ) ).toNumber(),
|
|
||||||
value.property( QStringLiteral( "color" ) ).toVariant().value< QColor >()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void QskQml::registerTypes()
|
void QskQml::registerTypes()
|
||||||
{
|
{
|
||||||
@ -420,10 +242,18 @@ void QskQml::registerTypes()
|
|||||||
|
|
||||||
registerNamespace( QskStandardSymbol::staticMetaObject );
|
registerNamespace( QskStandardSymbol::staticMetaObject );
|
||||||
|
|
||||||
QMetaType::registerConverter< QJSValue, QskGradientStop >( qskJSToGradientStop );
|
#if QT_VERSION < QT_VERSION_CHECK( 6, 5, 0 )
|
||||||
|
registerJSConverters();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK( 6, 2, 0 )
|
#if QT_VERSION < QT_VERSION_CHECK( 6, 2, 0 )
|
||||||
// how to do this with >= 6.2 TODO ...
|
/*
|
||||||
|
Since Qt 6.5 invokable constructors are accessible from QML, something
|
||||||
|
what was possibe until Qt 6.2 with string converters. For Qt [6.2,6.4]
|
||||||
|
we do not have any solution.
|
||||||
|
*/
|
||||||
|
|
||||||
QQmlMetaType::registerCustomStringConverter( qMetaTypeId< QskMargins >(),
|
QQmlMetaType::registerCustomStringConverter( qMetaTypeId< QskMargins >(),
|
||||||
[]( const QString& s ) { return QVariant::fromValue( QskMargins( s.toDouble() ) ); } );
|
[]( const QString& s ) { return QVariant::fromValue( QskMargins( s.toDouble() ) ); } );
|
||||||
#endif
|
#endif
|
||||||
|
293
qmlexport/QskQml.hpp
Normal file
293
qmlexport/QskQml.hpp
Normal file
@ -0,0 +1,293 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||||
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QSK_QML_HPP
|
||||||
|
#define QSK_QML_HPP
|
||||||
|
|
||||||
|
#include <qqml.h>
|
||||||
|
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK( 5, 14, 0 )
|
||||||
|
#include <qqmlengine.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#define QSK_MODULE_NAME "Skinny"
|
||||||
|
#define QSK_VERSION_MAJOR 1
|
||||||
|
#define QSK_VERSION_MINOR 0
|
||||||
|
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK( 6, 3, 0 )
|
||||||
|
#define QSK_STRUCT_VERSION 0
|
||||||
|
#elif QT_VERSION < QT_VERSION_CHECK( 6, 5, 0 )
|
||||||
|
#define QSK_STRUCT_VERSION 1
|
||||||
|
#else
|
||||||
|
#define QSK_STRUCT_VERSION 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Required for QFlags to be constructed from an enum value
|
||||||
|
#define QSK_REGISTER_FLAGS( Type ) \
|
||||||
|
QMetaType::registerConverter< int, Type >( []( int value ) { return Type( value ); } )
|
||||||
|
|
||||||
|
namespace QskQml
|
||||||
|
{
|
||||||
|
inline const char* classNameQml( const QMetaObject& metaObject )
|
||||||
|
{
|
||||||
|
// without the "Qsk" prefix
|
||||||
|
return metaObject.className() + 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
ClassInfo corresponds to the most reecent QQmlPrivate::RegisterType
|
||||||
|
( structVersion: 2 introduced with Qt 6.5 )
|
||||||
|
*/
|
||||||
|
class ClassInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
void setTypeInfo()
|
||||||
|
{
|
||||||
|
using namespace QQmlPrivate;
|
||||||
|
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
|
||||||
|
const char* className = T::staticMetaObject.className(); \
|
||||||
|
|
||||||
|
const int nameLen = int(strlen(className) ); \
|
||||||
|
const int listLen = int(strlen("QQmlListProperty<") ); \
|
||||||
|
|
||||||
|
QVarLengthArray< char,64 > listName(listLen + nameLen + 2); \
|
||||||
|
memcpy(listName.data(), "QQmlListProperty<", size_t(listLen) ); \
|
||||||
|
memcpy(listName.data() + listLen, className, size_t(nameLen) ); \
|
||||||
|
listName[listLen + nameLen] = '>'; \
|
||||||
|
listName[listLen + nameLen + 1] = '\0';
|
||||||
|
|
||||||
|
typeId = qMetaTypeId< T* >( );
|
||||||
|
listId = qRegisterNormalizedMetaType< QQmlListProperty< T > >( listName.constData() );
|
||||||
|
#else
|
||||||
|
if constexpr (std::is_base_of_v< QObject, T >)
|
||||||
|
{
|
||||||
|
typeId = QMetaType::fromType< T* >( );
|
||||||
|
listId = QMetaType::fromType< QQmlListProperty< T > >( );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
typeId = QMetaType::fromType< T >( );
|
||||||
|
listId = QMetaType::fromType< QList< T > >( );
|
||||||
|
}
|
||||||
|
|
||||||
|
createValueType = ValueType< T, void >::create;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
parserStatusCast = StaticCastSelector< T,QQmlParserStatus >::cast();
|
||||||
|
valueSourceCast = StaticCastSelector< T,QQmlPropertyValueSource >::cast();
|
||||||
|
valueInterceptorCast = StaticCastSelector< T,QQmlPropertyValueInterceptor >::cast();
|
||||||
|
#if QSK_STRUCT_VERSION >= 1
|
||||||
|
finalizerCast = StaticCastSelector< T,QQmlFinalizerHook >::cast();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
const int structVersion = QSK_STRUCT_VERSION;
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
|
||||||
|
QMetaType typeId;
|
||||||
|
QMetaType listId;
|
||||||
|
#else
|
||||||
|
int typeId = 0;
|
||||||
|
int listId = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int objectSize = 0;
|
||||||
|
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
|
||||||
|
void ( *create )( void* ) = nullptr;
|
||||||
|
#else
|
||||||
|
void ( *create )( void*, void* ) = nullptr;
|
||||||
|
void* const userdata = nullptr; // unused
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const QString noCreationReason; // unused
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
|
||||||
|
/*
|
||||||
|
This one was introdued with Qt 6.x, but never worked
|
||||||
|
as expected. With Qt 6.5 it has been replaced by adding
|
||||||
|
the creationMethod that is triggering to look for
|
||||||
|
invokable constructors.
|
||||||
|
Let's check if it makes any sense to initialize it below
|
||||||
|
at all. TODO ...
|
||||||
|
*/
|
||||||
|
QVariant ( *createValueType )( const QJSValue& ) = nullptr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char* const uri = QSK_MODULE_NAME;
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
|
||||||
|
const QTypeRevision version =
|
||||||
|
QTypeRevision::fromVersion( QSK_VERSION_MAJOR, QSK_VERSION_MINOR );
|
||||||
|
#else
|
||||||
|
const int versionMajor = QSK_VERSION_MAJOR;
|
||||||
|
const int versionMinor = QSK_VERSION_MINOR;
|
||||||
|
#endif
|
||||||
|
const char* elementName = nullptr;
|
||||||
|
const QMetaObject* metaObject = nullptr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
We do not use attached properties as it always comes with
|
||||||
|
creating extra QObjects.
|
||||||
|
*/
|
||||||
|
QObject* (* const attachedPropertiesFunction)( QObject* ) = nullptr;
|
||||||
|
const QMetaObject* const attachedPropertiesMetaObject = nullptr;
|
||||||
|
|
||||||
|
int parserStatusCast = -1;
|
||||||
|
int valueSourceCast = -1;
|
||||||
|
int valueInterceptorCast = -1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
We do not use extensions as it always comes with
|
||||||
|
creating extra QObjects.
|
||||||
|
*/
|
||||||
|
QObject* (* const extensionObjectCreate )( QObject* ) = nullptr;
|
||||||
|
const QMetaObject* const extensionMetaObject = nullptr;
|
||||||
|
|
||||||
|
void* const customParser = nullptr; // QQmlCustomParser, unused
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
|
||||||
|
const QTypeRevision revision = QTypeRevision::zero();
|
||||||
|
#else
|
||||||
|
const int revision = 0;
|
||||||
|
#endif
|
||||||
|
int finalizerCast = -1;
|
||||||
|
|
||||||
|
const int creationMethod = 2; // ValueTypeCreationMethod::Structured
|
||||||
|
};
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
inline int registerType( const char* qmlName )
|
||||||
|
{
|
||||||
|
using namespace QQmlPrivate;
|
||||||
|
|
||||||
|
ClassInfo type;
|
||||||
|
|
||||||
|
type.setTypeInfo< T >();
|
||||||
|
|
||||||
|
type.objectSize = sizeof( T );
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
|
||||||
|
type.create = Constructors< T >::createInto;
|
||||||
|
#else
|
||||||
|
type.create = createInto< T >;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
type.elementName = qmlName;
|
||||||
|
type.metaObject = &T::staticMetaObject;
|
||||||
|
|
||||||
|
return qmlregister( TypeRegistration, &type );
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
inline int registerUncreatableType( const char* qmlName )
|
||||||
|
{
|
||||||
|
using namespace QQmlPrivate;
|
||||||
|
|
||||||
|
ClassInfo type;
|
||||||
|
|
||||||
|
type.setTypeInfo< T >();
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
|
||||||
|
type.objectSize = sizeof( T );
|
||||||
|
type.create = Constructors< T >::createInto;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
type.elementName = qmlName;
|
||||||
|
type.metaObject = &T::staticMetaObject;
|
||||||
|
|
||||||
|
return qmlregister( TypeRegistration, &type );
|
||||||
|
}
|
||||||
|
|
||||||
|
int registerUncreatableMetaObject(
|
||||||
|
const QMetaObject& staticMetaObject, const char* qmlName )
|
||||||
|
{
|
||||||
|
using namespace QQmlPrivate;
|
||||||
|
|
||||||
|
ClassInfo type;
|
||||||
|
|
||||||
|
type.elementName = qmlName;
|
||||||
|
type.metaObject = &staticMetaObject;
|
||||||
|
|
||||||
|
return qmlregister( TypeRegistration, &type );
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
/*
|
||||||
|
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 ...
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( T::staticMetaObject.enumeratorCount() > 0 )
|
||||||
|
{
|
||||||
|
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 )
|
||||||
|
auto callback =
|
||||||
|
[]( QQmlEngine*, QJSEngine* )
|
||||||
|
{
|
||||||
|
QQmlEngine::setObjectOwnership( singleton, QQmlEngine::CppOwnership );
|
||||||
|
return singleton;
|
||||||
|
};
|
||||||
|
|
||||||
|
return qmlRegisterSingletonType< T >( QSK_MODULE_NAME,
|
||||||
|
QSK_VERSION_MAJOR, QSK_VERSION_MINOR, name, callback );
|
||||||
|
#else
|
||||||
|
return qmlRegisterSingletonInstance( QSK_MODULE_NAME,
|
||||||
|
QSK_VERSION_MAJOR, QSK_VERSION_MINOR, name, singleton );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -6,6 +6,9 @@ CONFIG += qskinny
|
|||||||
|
|
||||||
contains(QSK_CONFIG, QskDll): DEFINES += QSK_QML_MAKEDLL
|
contains(QSK_CONFIG, QskDll): DEFINES += QSK_QML_MAKEDLL
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
QskQml.hpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
QskQmlGlobal.h \
|
QskQmlGlobal.h \
|
||||||
QskShortcutQml.h \
|
QskShortcutQml.h \
|
||||||
|
@ -533,74 +533,6 @@ void QskGradient::resetDirection()
|
|||||||
m_values[0] = m_values[1] = m_values[2] = m_values[3] = 0.0;
|
m_values[0] = m_values[1] = m_values[2] = m_values[3] = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskGradient::setLinearAsList( const QVector< qreal >& params )
|
|
||||||
{
|
|
||||||
Q_ASSERT( params.size() == 4 );
|
|
||||||
|
|
||||||
m_type = Linear;
|
|
||||||
|
|
||||||
m_values[0] = params[0];
|
|
||||||
m_values[1] = params[1];
|
|
||||||
m_values[2] = params[2];
|
|
||||||
m_values[3] = params[3];
|
|
||||||
}
|
|
||||||
|
|
||||||
QVector< qreal > QskGradient::linearAsList() const
|
|
||||||
{
|
|
||||||
if ( m_type != Linear )
|
|
||||||
return { 0.0, 0.0, 0.0, 0.0 };
|
|
||||||
|
|
||||||
return { m_values[0], m_values[1], m_values[2], m_values[3] };
|
|
||||||
}
|
|
||||||
|
|
||||||
void QskGradient::setRadialAsList( const QVector< qreal >& params )
|
|
||||||
{
|
|
||||||
Q_ASSERT( params.size() == 3 );
|
|
||||||
|
|
||||||
m_type = Radial;
|
|
||||||
|
|
||||||
m_values[0] = params[0];
|
|
||||||
m_values[1] = params[1];
|
|
||||||
m_values[2] = params[2];
|
|
||||||
m_values[3] = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
QVector< qreal > QskGradient::radialAsList() const
|
|
||||||
{
|
|
||||||
if ( m_type != Radial )
|
|
||||||
return { 0.5, 0.5, 0.0 };
|
|
||||||
|
|
||||||
return { m_values[0], m_values[1], m_values[2] };
|
|
||||||
}
|
|
||||||
|
|
||||||
void QskGradient::setConicAsList( const QVector< qreal >& params )
|
|
||||||
{
|
|
||||||
Q_ASSERT( params.size() >= 2 && params.size() <= 4 );
|
|
||||||
|
|
||||||
m_type = Conic;
|
|
||||||
|
|
||||||
m_values[0] = params[0];
|
|
||||||
m_values[1] = params[1];
|
|
||||||
|
|
||||||
if ( params.size() > 2 )
|
|
||||||
m_values[2] = params[2];
|
|
||||||
else
|
|
||||||
m_values[2] = 0.0;
|
|
||||||
|
|
||||||
if ( params.size() == 4 )
|
|
||||||
m_values[3] = params[3];
|
|
||||||
else
|
|
||||||
m_values[2] = 360.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
QVector< qreal > QskGradient::conicAsList() const
|
|
||||||
{
|
|
||||||
if ( m_type != Conic )
|
|
||||||
return { 0.5, 0.5, 0.0, 0.0 };
|
|
||||||
|
|
||||||
return { m_values[0], m_values[1], m_values[2], m_values[3] };
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef QT_NO_DEBUG_STREAM
|
#ifndef QT_NO_DEBUG_STREAM
|
||||||
|
|
||||||
#include <qdebug.h>
|
#include <qdebug.h>
|
||||||
|
@ -28,6 +28,10 @@ class QSK_EXPORT QskGradient
|
|||||||
|
|
||||||
Q_PROPERTY( Type type READ type )
|
Q_PROPERTY( Type type READ type )
|
||||||
|
|
||||||
|
Q_PROPERTY( QskLinearDirection linear READ linearDirection WRITE setLinearDirection )
|
||||||
|
Q_PROPERTY( QskConicDirection conic READ conicDirection WRITE setConicDirection )
|
||||||
|
Q_PROPERTY( QskRadialDirection radial READ radialDirection WRITE setRadialDirection )
|
||||||
|
|
||||||
Q_PROPERTY( QVector< QskGradientStop > stops READ stops WRITE setStops )
|
Q_PROPERTY( QVector< QskGradientStop > stops READ stops WRITE setStops )
|
||||||
|
|
||||||
Q_PROPERTY( bool valid READ isValid )
|
Q_PROPERTY( bool valid READ isValid )
|
||||||
@ -134,27 +138,6 @@ class QSK_EXPORT QskGradient
|
|||||||
private:
|
private:
|
||||||
void updateStatusBits() const;
|
void updateStatusBits() const;
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
Q_PROPERTY( QVector< qreal > linear READ linearAsList WRITE setLinearAsList )
|
|
||||||
Q_PROPERTY( QVector< qreal > conic READ conicAsList WRITE setConicAsList )
|
|
||||||
Q_PROPERTY( QVector< qreal > radial READ radialAsList WRITE setRadialAsList )
|
|
||||||
#else
|
|
||||||
Q_PROPERTY( QskLinearDirection linear READ linearDirection WRITE setLinearDirection )
|
|
||||||
Q_PROPERTY( QskConicDirection conic READ conicDirection WRITE setConicDirection )
|
|
||||||
Q_PROPERTY( QskRadialDirection radial READ radialDirection WRITE setRadialDirection )
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QVector< qreal > linearAsList() const;
|
|
||||||
void setLinearAsList( const QVector< qreal >& );
|
|
||||||
|
|
||||||
QVector< qreal > radialAsList() const;
|
|
||||||
void setRadialAsList( const QVector< qreal >& );
|
|
||||||
|
|
||||||
QVector< qreal > conicAsList() const;
|
|
||||||
void setConicAsList( const QVector< qreal >& );
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QVector< QskGradientStop > m_stops;
|
QVector< QskGradientStop > m_stops;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user