qskinny/src/controls/QskSkin.cpp

377 lines
9.6 KiB
C++
Raw Normal View History

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"
#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"
#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"
static inline QskSkinlet* qskNewSkinlet( const QMetaObject* metaObject, QskSkin* skin )
{
const QByteArray signature = metaObject->className() + QByteArrayLiteral( "(QskSkin*)" );
QskSkinlet* skinlet = nullptr;
const int index = metaObject->indexOfConstructor( signature.constData() );
if ( index >= 0 )
{
void* param[] = { &skinlet, &skin };
metaObject->static_metacall( QMetaObject::CreateInstance, index, param );
}
return skinlet;
}
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;
QskSkinHintTable hintTable;
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 >();
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() );
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-26 12:57:08 +01:00
QskSkin::~QskSkin()
{
}
2020-12-21 16:06:58 +01:00
void QskSkin::setSkinHint( QskAspect aspect, const QVariant& skinHint )
2017-07-21 18:21:34 +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
{
return m_data->hintTable.hint( aspect );
2017-07-21 18:21:34 +02:00
}
void QskSkin::declareSkinlet( const QMetaObject* metaObject,
const QMetaObject* skinletMetaObject )
{
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();
}
const QskSkinHintTable& QskSkin::hintTable() const
2017-07-21 18:21:34 +02:00
{
return m_data->hintTable;
}
2020-12-26 12:57:08 +01:00
QskSkinHintTable& QskSkin::hintTable()
{
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 );
}
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 )
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"