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 "QskSkin.h"
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
#include "QskAnimationHint.h"
|
2017-07-21 18:21:34 +02:00
|
|
|
#include "QskAspect.h"
|
|
|
|
#include "QskColorFilter.h"
|
2018-08-03 08:15:28 +02:00
|
|
|
#include "QskGraphic.h"
|
2017-07-21 18:21:34 +02:00
|
|
|
#include "QskGraphicProviderMap.h"
|
2017-08-22 20:50:55 +02:00
|
|
|
#include "QskSkinHintTable.h"
|
2018-08-03 08:15:28 +02:00
|
|
|
#include "QskStandardSymbol.h"
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2020-12-26 12:57:08 +01:00
|
|
|
#include "QskMargins.h"
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
QSK_QT_PRIVATE_BEGIN
|
|
|
|
#include <private/qguiapplication_p.h>
|
|
|
|
QSK_QT_PRIVATE_END
|
|
|
|
|
|
|
|
#include <qpa/qplatformdialoghelper.h>
|
2018-08-03 08:15:28 +02:00
|
|
|
#include <qpa/qplatformtheme.h>
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
#include <cmath>
|
2018-08-03 08:15:28 +02:00
|
|
|
#include <unordered_map>
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
#include "QskBox.h"
|
|
|
|
#include "QskBoxSkinlet.h"
|
|
|
|
|
|
|
|
#include "QskFocusIndicator.h"
|
|
|
|
#include "QskFocusIndicatorSkinlet.h"
|
|
|
|
|
|
|
|
#include "QskGraphicLabel.h"
|
|
|
|
#include "QskGraphicLabelSkinlet.h"
|
|
|
|
|
|
|
|
#include "QskListView.h"
|
|
|
|
#include "QskListViewSkinlet.h"
|
|
|
|
|
|
|
|
#include "QskPopup.h"
|
|
|
|
#include "QskPopupSkinlet.h"
|
|
|
|
|
|
|
|
#include "QskPushButton.h"
|
|
|
|
#include "QskPushButtonSkinlet.h"
|
|
|
|
|
|
|
|
#include "QskScrollView.h"
|
|
|
|
#include "QskScrollViewSkinlet.h"
|
|
|
|
|
|
|
|
#include "QskSlider.h"
|
|
|
|
#include "QskSliderSkinlet.h"
|
|
|
|
|
|
|
|
#include "QskTabButton.h"
|
|
|
|
#include "QskTabButtonSkinlet.h"
|
|
|
|
|
|
|
|
#include "QskTabView.h"
|
|
|
|
#include "QskTabViewSkinlet.h"
|
|
|
|
|
|
|
|
#include "QskTextLabel.h"
|
|
|
|
#include "QskTextLabelSkinlet.h"
|
|
|
|
|
2018-04-03 10:47:21 +02:00
|
|
|
#include "QskTextInput.h"
|
|
|
|
#include "QskTextInputSkinlet.h"
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
#include "QskSeparator.h"
|
|
|
|
#include "QskSeparatorSkinlet.h"
|
|
|
|
|
|
|
|
#include "QskSubWindow.h"
|
|
|
|
#include "QskSubWindowSkinlet.h"
|
|
|
|
|
|
|
|
#include "QskSubWindowArea.h"
|
|
|
|
#include "QskSubWindowAreaSkinlet.h"
|
|
|
|
|
2021-08-02 13:22:37 +02:00
|
|
|
#include "QskSwitchButton.h"
|
|
|
|
#include "QskSwitchButtonSkinlet.h"
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
#include "QskPageIndicator.h"
|
|
|
|
#include "QskPageIndicatorSkinlet.h"
|
|
|
|
|
2020-08-01 17:51:45 +02:00
|
|
|
#include "QskProgressBar.h"
|
|
|
|
#include "QskProgressBarSkinlet.h"
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
#include "QskStatusIndicator.h"
|
|
|
|
#include "QskStatusIndicatorSkinlet.h"
|
|
|
|
|
2019-09-10 17:01:47 +02:00
|
|
|
static inline QskSkinlet* qskNewSkinlet( const QMetaObject* metaObject, QskSkin* skin )
|
2019-06-25 20:27:40 +02:00
|
|
|
{
|
|
|
|
const QByteArray signature = metaObject->className() + QByteArrayLiteral( "(QskSkin*)" );
|
|
|
|
|
2019-09-10 17:01:47 +02:00
|
|
|
QskSkinlet* skinlet = nullptr;
|
2019-06-25 20:27:40 +02:00
|
|
|
|
|
|
|
const int index = metaObject->indexOfConstructor( signature.constData() );
|
|
|
|
if ( index >= 0 )
|
|
|
|
{
|
2019-09-10 17:01:47 +02:00
|
|
|
void* param[] = { &skinlet, &skin };
|
2019-06-25 20:27:40 +02:00
|
|
|
metaObject->static_metacall( QMetaObject::CreateInstance, index, param );
|
|
|
|
}
|
|
|
|
|
|
|
|
return skinlet;
|
2019-09-10 17:01:47 +02:00
|
|
|
}
|
2019-06-25 20:27:40 +02:00
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
class SkinletData
|
|
|
|
{
|
2018-08-03 08:15:28 +02:00
|
|
|
public:
|
|
|
|
SkinletData( const QMetaObject* metaObject )
|
|
|
|
: metaObject( metaObject )
|
|
|
|
, skinlet( nullptr )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
~SkinletData()
|
|
|
|
{
|
|
|
|
delete skinlet;
|
|
|
|
}
|
|
|
|
|
|
|
|
const QMetaObject* metaObject;
|
|
|
|
QskSkinlet* skinlet;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
class QskSkin::PrivateData
|
|
|
|
{
|
2018-08-03 08:15:28 +02:00
|
|
|
public:
|
2017-07-21 18:21:34 +02:00
|
|
|
std::unordered_map< const QMetaObject*, SkinletData > skinletMap;
|
|
|
|
|
2017-08-22 20:50:55 +02:00
|
|
|
QskSkinHintTable hintTable;
|
2020-03-19 14:10:50 +01:00
|
|
|
QskAspect::State stateMask = QskAspect::AllStates;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
std::unordered_map< int, QFont > fonts;
|
|
|
|
std::unordered_map< int, QskColorFilter > graphicFilters;
|
|
|
|
|
|
|
|
QskGraphicProviderMap graphicProviders;
|
|
|
|
};
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
QskSkin::QskSkin( QObject* parent )
|
|
|
|
: QObject( parent )
|
2019-02-28 08:07:05 +01:00
|
|
|
, m_data( new PrivateData() )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
declareSkinlet< QskControl, QskSkinlet >();
|
|
|
|
|
|
|
|
declareSkinlet< QskBox, QskBoxSkinlet >();
|
|
|
|
declareSkinlet< QskFocusIndicator, QskFocusIndicatorSkinlet >();
|
|
|
|
declareSkinlet< QskGraphicLabel, QskGraphicLabelSkinlet >();
|
|
|
|
declareSkinlet< QskListView, QskListViewSkinlet >();
|
|
|
|
declareSkinlet< QskPageIndicator, QskPageIndicatorSkinlet >();
|
|
|
|
declareSkinlet< QskPopup, QskPopupSkinlet >();
|
|
|
|
declareSkinlet< QskPushButton, QskPushButtonSkinlet >();
|
|
|
|
declareSkinlet< QskScrollView, QskScrollViewSkinlet >();
|
|
|
|
declareSkinlet< QskSeparator, QskSeparatorSkinlet >();
|
|
|
|
declareSkinlet< QskSlider, QskSliderSkinlet >();
|
|
|
|
declareSkinlet< QskStatusIndicator, QskStatusIndicatorSkinlet >();
|
|
|
|
declareSkinlet< QskSubWindow, QskSubWindowSkinlet >();
|
|
|
|
declareSkinlet< QskSubWindowArea, QskSubWindowAreaSkinlet >();
|
2021-08-02 13:22:37 +02:00
|
|
|
declareSkinlet< QskSwitchButton, QskSwitchButtonSkinlet >();
|
2017-07-21 18:21:34 +02:00
|
|
|
declareSkinlet< QskTabButton, QskTabButtonSkinlet >();
|
|
|
|
declareSkinlet< QskTabView, QskTabViewSkinlet >();
|
|
|
|
declareSkinlet< QskTextLabel, QskTextLabelSkinlet >();
|
2018-04-03 10:47:21 +02:00
|
|
|
declareSkinlet< QskTextInput, QskTextInputSkinlet >();
|
2020-08-01 17:51:45 +02:00
|
|
|
declareSkinlet< QskProgressBar, QskProgressBarSkinlet >();
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
const QFont font = QGuiApplication::font();
|
|
|
|
setupFonts( font.family(), font.weight(), font.italic() );
|
2017-08-28 13:20:01 +02:00
|
|
|
|
2020-12-26 12:57:08 +01:00
|
|
|
{
|
|
|
|
// some defaults
|
|
|
|
const auto noMargins = QVariant::fromValue( QskMargins( 0 ) );
|
|
|
|
const auto aspect = QskAspect::Control | QskAspect::Metric;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2020-12-26 12:57:08 +01:00
|
|
|
setSkinHint( aspect | QskAspect::Margin, noMargins );
|
|
|
|
setSkinHint( aspect | QskAspect::Padding, noMargins );
|
|
|
|
setSkinHint( aspect | QskAspect::Spacing, 0 );
|
|
|
|
}
|
2020-12-15 07:21:12 +01:00
|
|
|
}
|
|
|
|
|
2020-12-26 12:57:08 +01:00
|
|
|
QskSkin::~QskSkin()
|
2020-12-15 07:21:12 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-12-21 16:06:58 +01:00
|
|
|
void QskSkin::setSkinHint( QskAspect aspect, const QVariant& skinHint )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2017-10-17 17:34:00 +02:00
|
|
|
m_data->hintTable.setHint( aspect, skinHint );
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
2020-12-21 16:06:58 +01:00
|
|
|
const QVariant& QskSkin::skinHint( QskAspect aspect ) const
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2017-10-17 17:34:00 +02:00
|
|
|
return m_data->hintTable.hint( aspect );
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void QskSkin::declareSkinlet( const QMetaObject* metaObject,
|
|
|
|
const QMetaObject* skinletMetaObject )
|
|
|
|
{
|
2020-07-31 07:39:14 +02:00
|
|
|
Q_ASSERT( skinletMetaObject->constructorCount() );
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
const auto it = m_data->skinletMap.find( metaObject );
|
|
|
|
|
|
|
|
if ( it != m_data->skinletMap.cend() )
|
|
|
|
{
|
|
|
|
auto& entry = it->second;
|
|
|
|
if ( entry.metaObject != skinletMetaObject )
|
|
|
|
{
|
|
|
|
entry.metaObject = skinletMetaObject;
|
2021-01-12 16:25:33 +01:00
|
|
|
|
|
|
|
delete entry.skinlet;
|
|
|
|
entry.skinlet = nullptr;
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_data->skinletMap.emplace( metaObject, skinletMetaObject );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskSkin::setupFonts( const QString& family, int weight, bool italic )
|
|
|
|
{
|
|
|
|
QFont font( family, -1, weight, italic );
|
|
|
|
|
|
|
|
const uint base = TinyFont;
|
|
|
|
for ( int i = TinyFont; i <= HugeFont; i++ )
|
|
|
|
{
|
|
|
|
// TODO: make the scaling components configurable
|
|
|
|
font.setPixelSize( int( std::pow( uint( i ) - base + 2, 2.5 ) ) );
|
|
|
|
m_data->fonts[ i ] = font;
|
|
|
|
}
|
|
|
|
|
|
|
|
const QFont appFont( QGuiApplication::font() );
|
|
|
|
if ( appFont.pixelSize() > 0 )
|
|
|
|
font.setPixelSize( appFont.pixelSize() );
|
|
|
|
else
|
|
|
|
font.setPointSize( appFont.pointSize() );
|
|
|
|
|
|
|
|
m_data->fonts[ QskSkin::DefaultFont ] = font;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskSkin::setFont( int fontRole, const QFont& font )
|
|
|
|
{
|
|
|
|
m_data->fonts[ fontRole ] = font;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskSkin::resetFont( int fontRole )
|
|
|
|
{
|
|
|
|
m_data->fonts.erase( fontRole );
|
|
|
|
}
|
|
|
|
|
|
|
|
QFont QskSkin::font( int fontRole ) const
|
|
|
|
{
|
|
|
|
auto it = m_data->fonts.find( fontRole );
|
|
|
|
if ( it != m_data->fonts.cend() )
|
|
|
|
return it->second;
|
|
|
|
|
|
|
|
it = m_data->fonts.find( QskSkin::DefaultFont );
|
|
|
|
if ( it != m_data->fonts.cend() )
|
|
|
|
return it->second;
|
|
|
|
|
|
|
|
return QGuiApplication::font();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskSkin::setGraphicFilter( int graphicRole, const QskColorFilter& colorFilter )
|
|
|
|
{
|
|
|
|
m_data->graphicFilters[ graphicRole ] = colorFilter;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskSkin::resetGraphicFilter( int graphicRole )
|
|
|
|
{
|
|
|
|
m_data->graphicFilters.erase( graphicRole );
|
|
|
|
}
|
|
|
|
|
|
|
|
QskColorFilter QskSkin::graphicFilter( int graphicRole ) const
|
|
|
|
{
|
|
|
|
auto it = m_data->graphicFilters.find( graphicRole );
|
|
|
|
if ( it != m_data->graphicFilters.cend() )
|
|
|
|
return it->second;
|
|
|
|
|
|
|
|
return QskColorFilter();
|
|
|
|
}
|
|
|
|
|
2017-08-22 20:50:55 +02:00
|
|
|
const QskSkinHintTable& QskSkin::hintTable() const
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2017-08-22 20:50:55 +02:00
|
|
|
return m_data->hintTable;
|
|
|
|
}
|
|
|
|
|
2020-12-26 12:57:08 +01:00
|
|
|
QskSkinHintTable& QskSkin::hintTable()
|
2017-08-22 20:50:55 +02:00
|
|
|
{
|
|
|
|
return m_data->hintTable;
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const std::unordered_map< int, QFont >& QskSkin::fonts() const
|
|
|
|
{
|
|
|
|
return m_data->fonts;
|
|
|
|
}
|
|
|
|
|
|
|
|
const std::unordered_map< int, QskColorFilter >& QskSkin::graphicFilters() const
|
|
|
|
{
|
|
|
|
return m_data->graphicFilters;
|
|
|
|
}
|
|
|
|
|
|
|
|
QskGraphic QskSkin::symbol( int symbolType ) const
|
|
|
|
{
|
|
|
|
// should this one be somehow related to the platform icons ???
|
|
|
|
return QskStandardSymbol::graphic(
|
|
|
|
static_cast< QskStandardSymbol::Type >( symbolType ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskSkin::addGraphicProvider(
|
|
|
|
const QString& providerId, QskGraphicProvider* provider )
|
|
|
|
{
|
|
|
|
m_data->graphicProviders.insert( providerId, provider );
|
|
|
|
}
|
|
|
|
|
|
|
|
QskGraphicProvider* QskSkin::graphicProvider( const QString& providerId ) const
|
|
|
|
{
|
|
|
|
return m_data->graphicProviders.provider( providerId );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QskSkin::hasGraphicProvider() const
|
|
|
|
{
|
|
|
|
return m_data->graphicProviders.size() > 0;
|
|
|
|
}
|
|
|
|
|
2018-03-22 11:20:13 +01:00
|
|
|
const int* QskSkin::dialogButtonLayout( Qt::Orientation orientation ) const
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2018-08-03 08:15:28 +02:00
|
|
|
// auto policy = QPlatformDialogHelper::UnknownLayout;
|
2017-07-21 18:21:34 +02:00
|
|
|
auto policy = QPlatformDialogHelper::WinLayout;
|
|
|
|
|
2018-04-03 20:15:20 +02:00
|
|
|
if ( const auto theme = QGuiApplicationPrivate::platformTheme() )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
const QVariant v = theme->themeHint( QPlatformTheme::DialogButtonBoxLayout );
|
2018-03-22 11:20:13 +01:00
|
|
|
policy = static_cast< QPlatformDialogHelper::ButtonLayout >( v.toInt() );
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return QPlatformDialogHelper::buttonLayout( orientation, policy );
|
|
|
|
}
|
|
|
|
|
2020-03-19 14:10:50 +01:00
|
|
|
void QskSkin::setStateMask( QskAspect::State mask )
|
|
|
|
{
|
|
|
|
for ( auto state : { QskControl::Disabled, QskControl::Hovered, QskControl::Focused } )
|
|
|
|
{
|
|
|
|
if ( mask & state )
|
|
|
|
m_data->stateMask |= state;
|
|
|
|
else
|
|
|
|
m_data->stateMask &= ~state;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QskAspect::State QskSkin::stateMask() const
|
|
|
|
{
|
|
|
|
return m_data->stateMask;
|
|
|
|
}
|
|
|
|
|
2020-12-23 09:41:29 +01:00
|
|
|
QskSkinlet* QskSkin::skinlet( const QMetaObject* metaObject )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2020-12-23 09:41:29 +01:00
|
|
|
while ( metaObject )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
auto it = m_data->skinletMap.find( metaObject );
|
|
|
|
if ( it != m_data->skinletMap.cend() )
|
|
|
|
{
|
|
|
|
auto& entry = it->second;
|
|
|
|
|
|
|
|
if ( entry.skinlet == nullptr )
|
2019-06-25 20:27:40 +02:00
|
|
|
entry.skinlet = qskNewSkinlet( entry.metaObject, this );
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
return entry.skinlet;
|
|
|
|
}
|
2020-12-23 09:41:29 +01:00
|
|
|
|
|
|
|
metaObject = metaObject->superClass();
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static QskSkinlet defaultSkinlet;
|
|
|
|
return &defaultSkinlet;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskSkin::resetColors( const QColor& )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "moc_QskSkin.cpp"
|