2017-07-21 18:21:34 +02:00
|
|
|
/******************************************************************************
|
|
|
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
|
|
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
#include "QskSetup.h"
|
2018-08-03 08:15:28 +02:00
|
|
|
#include "QskControl.h"
|
2019-09-04 06:59:43 +02:00
|
|
|
#include "QskControlPrivate.h"
|
2018-08-03 08:15:28 +02:00
|
|
|
#include "QskGraphicProviderMap.h"
|
|
|
|
#include "QskObjectTree.h"
|
2017-07-21 18:21:34 +02:00
|
|
|
#include "QskSkin.h"
|
2018-01-03 11:57:05 +01:00
|
|
|
#include "QskSkinManager.h"
|
2017-07-21 18:21:34 +02:00
|
|
|
#include "QskWindow.h"
|
|
|
|
|
2018-07-19 14:10:48 +02:00
|
|
|
#include <qguiapplication.h>
|
2018-08-03 08:15:28 +02:00
|
|
|
#include <qpointer.h>
|
2018-07-19 14:10:48 +02:00
|
|
|
#include <qstylehints.h>
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
QskSetup* QskSetup::s_instance = nullptr;
|
|
|
|
|
|
|
|
static inline bool qskHasEnvironment( const char* env )
|
|
|
|
{
|
|
|
|
bool ok;
|
|
|
|
|
|
|
|
const int value = qEnvironmentVariableIntValue( env, &ok );
|
|
|
|
if ( ok )
|
|
|
|
return value != 0;
|
|
|
|
|
|
|
|
// All other strings are true, apart from "false"
|
|
|
|
auto result = qgetenv( env );
|
|
|
|
return !result.isEmpty() && result != "false";
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline const QskSetup::Flags qskEnvironmentFlags()
|
|
|
|
{
|
|
|
|
QskSetup::Flags flags;
|
|
|
|
|
|
|
|
if ( qskHasEnvironment( "QSK_PREFER_RASTER" ) )
|
|
|
|
flags |= QskSetup::PreferRasterForTextures;
|
|
|
|
|
|
|
|
if ( qskHasEnvironment( "QSK_FORCE_BACKGROUND" ) )
|
|
|
|
flags |= QskSetup::DebugForceBackground;
|
|
|
|
|
|
|
|
return flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline QskSetup::Flags qskDefaultControlFlags()
|
|
|
|
{
|
|
|
|
static QskSetup::Flags flags;
|
|
|
|
|
|
|
|
if ( flags == 0 )
|
|
|
|
{
|
|
|
|
flags |= QskSetup::DeferredUpdate;
|
|
|
|
flags |= QskSetup::DeferredPolish;
|
|
|
|
flags |= QskSetup::DeferredLayout;
|
|
|
|
flags |= QskSetup::CleanupOnVisibility;
|
|
|
|
flags |= qskEnvironmentFlags();
|
|
|
|
}
|
|
|
|
|
|
|
|
return flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void qskApplicationHook()
|
|
|
|
{
|
|
|
|
QskSetup::setup();
|
|
|
|
qAddPostRoutine( QskSetup::cleanup );
|
|
|
|
}
|
|
|
|
|
2017-10-24 19:32:54 +02:00
|
|
|
static void qskApplicationFilter()
|
|
|
|
{
|
|
|
|
QCoreApplication::instance()->installEventFilter( QskSetup::instance() );
|
|
|
|
}
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
Q_CONSTRUCTOR_FUNCTION( qskApplicationHook )
|
2017-10-24 19:32:54 +02:00
|
|
|
Q_COREAPP_STARTUP_FUNCTION( qskApplicationFilter )
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
extern bool qskInheritLocale( QskWindow*, const QLocale& );
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
class VisitorLocale final : public QskObjectTree::ResolveVisitor< QLocale >
|
|
|
|
{
|
2018-08-03 08:15:28 +02:00
|
|
|
public:
|
|
|
|
VisitorLocale()
|
|
|
|
: ResolveVisitor< QLocale >( "locale" )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
private:
|
|
|
|
bool setImplicitValue( QskControl* control,
|
|
|
|
const QLocale& locale ) override
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2019-09-04 06:59:43 +02:00
|
|
|
return QskControlPrivate::inheritLocale( control, locale );
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
bool setImplicitValue( QskWindow* window,
|
|
|
|
const QLocale& locale ) override
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
return qskInheritLocale( window, locale );
|
|
|
|
}
|
|
|
|
|
2018-07-31 17:32:25 +02:00
|
|
|
QLocale value( const QskControl* control ) const override
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
return control->locale();
|
|
|
|
}
|
|
|
|
|
2018-07-31 17:32:25 +02:00
|
|
|
QLocale value( const QskWindow* window ) const override
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
return window->locale();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
class QskSetup::PrivateData
|
|
|
|
{
|
2018-08-03 08:15:28 +02:00
|
|
|
public:
|
|
|
|
PrivateData()
|
|
|
|
: controlFlags( qskDefaultControlFlags() )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
QString skinName;
|
|
|
|
QPointer< QskSkin > skin;
|
|
|
|
|
|
|
|
QskGraphicProviderMap graphicProviders;
|
|
|
|
QskSetup::Flags controlFlags;
|
|
|
|
};
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
QskSetup::QskSetup()
|
|
|
|
: m_data( new PrivateData() )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
QskSetup::~QskSetup()
|
|
|
|
{
|
|
|
|
s_instance = nullptr; // we might be destroyed from Qml !
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskSetup::setup()
|
|
|
|
{
|
|
|
|
if ( s_instance == nullptr )
|
|
|
|
s_instance = new QskSetup();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskSetup::cleanup()
|
|
|
|
{
|
|
|
|
if ( s_instance )
|
|
|
|
{
|
|
|
|
delete s_instance;
|
|
|
|
s_instance = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskSetup::setControlFlags( QskSetup::Flags flags )
|
|
|
|
{
|
|
|
|
if ( m_data->controlFlags != flags )
|
|
|
|
{
|
|
|
|
m_data->controlFlags = flags;
|
|
|
|
Q_EMIT controlFlagsChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QskSetup::Flags QskSetup::controlFlags() const
|
|
|
|
{
|
|
|
|
return m_data->controlFlags;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskSetup::resetControlFlags()
|
|
|
|
{
|
|
|
|
setControlFlags( qskDefaultControlFlags() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskSetup::setControlFlag( QskSetup::Flag flag, bool on )
|
|
|
|
{
|
|
|
|
if ( m_data->controlFlags.testFlag( flag ) != on )
|
|
|
|
{
|
|
|
|
if ( on )
|
|
|
|
m_data->controlFlags |= flag;
|
|
|
|
else
|
|
|
|
m_data->controlFlags &= ~flag;
|
|
|
|
|
|
|
|
Q_EMIT controlFlagsChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskSetup::resetControlFlag( QskSetup::Flag flag )
|
|
|
|
{
|
|
|
|
setControlFlag( flag, flag & qskDefaultControlFlags() );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QskSetup::testControlFlag( QskSetup::Flag flag )
|
|
|
|
{
|
|
|
|
return m_data->controlFlags.testFlag( flag );
|
|
|
|
}
|
|
|
|
|
|
|
|
QskSkin* QskSetup::setSkin( const QString& skinName )
|
|
|
|
{
|
|
|
|
if ( m_data->skin && ( skinName == m_data->skinName ) )
|
|
|
|
return m_data->skin;
|
|
|
|
|
2018-01-03 11:57:05 +01:00
|
|
|
QskSkin* skin = QskSkinManager::instance()->createSkin( skinName );
|
2017-07-21 18:21:34 +02:00
|
|
|
if ( skin == nullptr )
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
if ( skin->parent() == nullptr )
|
|
|
|
skin->setParent( this );
|
|
|
|
|
|
|
|
const QskSkin* oldSkin = m_data->skin;
|
|
|
|
|
|
|
|
m_data->skin = skin;
|
|
|
|
m_data->skinName = skinName;
|
|
|
|
|
|
|
|
if ( oldSkin )
|
|
|
|
{
|
|
|
|
Q_EMIT skinChanged( skin );
|
|
|
|
|
|
|
|
if ( oldSkin->parent() == this )
|
|
|
|
delete oldSkin;
|
|
|
|
}
|
|
|
|
|
|
|
|
return m_data->skin;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString QskSetup::skinName() const
|
|
|
|
{
|
|
|
|
return m_data->skinName;
|
|
|
|
}
|
|
|
|
|
|
|
|
QskSkin* QskSetup::skin()
|
|
|
|
{
|
|
|
|
if ( m_data->skin == nullptr )
|
|
|
|
{
|
2018-01-16 20:34:54 +01:00
|
|
|
m_data->skin = QskSkinManager::instance()->createSkin( QString() );
|
2018-01-03 11:57:05 +01:00
|
|
|
Q_ASSERT( m_data->skin );
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
m_data->skin->setParent( this );
|
|
|
|
m_data->skinName = m_data->skin->objectName();
|
|
|
|
}
|
|
|
|
|
|
|
|
return m_data->skin;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskSetup::addGraphicProvider( const QString& providerId, QskGraphicProvider* provider )
|
|
|
|
{
|
|
|
|
m_data->graphicProviders.insert( providerId, provider );
|
2017-10-24 19:32:54 +02:00
|
|
|
}
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
QskGraphicProvider* QskSetup::graphicProvider( const QString& providerId ) const
|
|
|
|
{
|
|
|
|
if ( m_data->skin )
|
|
|
|
{
|
|
|
|
QskGraphicProvider* provider = m_data->skin->graphicProvider( providerId );
|
|
|
|
if ( provider )
|
|
|
|
return provider;
|
|
|
|
}
|
|
|
|
|
|
|
|
return m_data->graphicProviders.provider( providerId );
|
2017-10-24 19:32:54 +02:00
|
|
|
}
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
QLocale QskSetup::inheritedLocale( const QObject* object )
|
|
|
|
{
|
|
|
|
VisitorLocale visitor;
|
|
|
|
visitor.setResolveValue( QLocale() );
|
|
|
|
|
|
|
|
QskObjectTree::traverseUp( const_cast< QObject* >( object ), visitor );
|
|
|
|
return visitor.resolveValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskSetup::inheritLocale( QObject* object, const QLocale& locale )
|
|
|
|
{
|
|
|
|
VisitorLocale visitor;
|
|
|
|
visitor.setResolveValue( locale );
|
|
|
|
|
|
|
|
QskObjectTree::traverseDown( object, visitor );
|
|
|
|
}
|
|
|
|
|
2017-10-24 19:32:54 +02:00
|
|
|
bool QskSetup::eventFilter( QObject* object, QEvent* event )
|
|
|
|
{
|
2019-04-26 11:56:09 +02:00
|
|
|
if ( auto control = qskControlCast( object ) )
|
2017-10-24 19:32:54 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
Qt::FocusPolicy has always been there with widgets, got lost with
|
|
|
|
Qt/Quick and has been reintroduced with Qt/Quick Controls 2 ( QC2 ).
|
|
|
|
Unfortunately this was done once more by adding code on top instead
|
|
|
|
of fixing the foundation.
|
|
|
|
|
|
|
|
But we also don't want to have how it is done in QC2 by adding
|
|
|
|
the focus management in the event handler of the base class.
|
2018-01-19 10:07:05 +01:00
|
|
|
This implementation reverts the expected default behaviour of when
|
2017-10-24 19:32:54 +02:00
|
|
|
events are accepted/ignored + is an error prone nightmare, when it
|
|
|
|
comes to overloading event handlers missing to call the base class.
|
|
|
|
|
|
|
|
That's why we prefer to do the focus management outside of the
|
|
|
|
event handlers.
|
|
|
|
*/
|
2018-08-03 08:15:28 +02:00
|
|
|
switch ( event->type() )
|
2017-10-24 19:32:54 +02:00
|
|
|
{
|
|
|
|
case QEvent::MouseButtonPress:
|
|
|
|
case QEvent::MouseButtonRelease:
|
|
|
|
{
|
|
|
|
if ( ( control->focusPolicy() & Qt::ClickFocus ) == Qt::ClickFocus )
|
|
|
|
{
|
|
|
|
const bool focusOnRelease =
|
|
|
|
QGuiApplication::styleHints()->setFocusOnTouchRelease();
|
|
|
|
|
|
|
|
if ( focusOnRelease )
|
|
|
|
{
|
|
|
|
if ( event->type() == QEvent::MouseButtonRelease )
|
|
|
|
control->forceActiveFocus( Qt::MouseFocusReason );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( event->type() == QEvent::MouseButtonPress )
|
|
|
|
control->forceActiveFocus( Qt::MouseFocusReason );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case QEvent::Wheel:
|
|
|
|
{
|
|
|
|
if ( !control->isWheelEnabled() )
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
We block further processing of the event. This is in line
|
|
|
|
with not receiving any mouse event that have not been
|
|
|
|
explicitly enabled with setAcceptedMouseButtons().
|
|
|
|
|
|
|
|
*/
|
|
|
|
event->ignore();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ( control->focusPolicy() & Qt::WheelFocus ) == Qt::WheelFocus )
|
|
|
|
control->forceActiveFocus( Qt::MouseFocusReason );
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
QskSetup* QskSetup::qmlAttachedProperties( QObject* )
|
|
|
|
{
|
|
|
|
return QskSetup::instance();
|
|
|
|
}
|
|
|
|
|
|
|
|
Q_DECLARE_METATYPE( QskSkin* )
|
|
|
|
#include "moc_QskSetup.cpp"
|