qskinny/src/controls/QskSkin.cpp

554 lines
14 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
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"
#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 >();
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() );
setMargin( QskAspect::Control, 0 );
setPadding( QskAspect::Control, 0 );
setSpacing( QskAspect::Control, 0 );
2017-07-21 18:21:34 +02:00
}
QskSkin::~QskSkin()
{
}
2020-12-21 16:06:58 +01:00
void QskSkin::setColor( QskAspect aspect, QRgb rgb )
2017-07-21 18:21:34 +02:00
{
setSkinHint( aspect | QskAspect::Color, QColor::fromRgba( rgb ) );
}
2020-12-21 16:06:58 +01:00
void QskSkin::setColor( QskAspect aspect, Qt::GlobalColor color )
2017-07-21 18:21:34 +02:00
{
setSkinHint( aspect | QskAspect::Color, QColor( color ) );
}
2020-12-21 16:06:58 +01:00
void QskSkin::setColor( QskAspect aspect, const QColor& color )
2017-07-21 18:21:34 +02:00
{
setSkinHint( aspect | QskAspect::Color, color );
}
2020-12-21 16:06:58 +01:00
QColor QskSkin::color( QskAspect aspect ) const
2017-07-21 18:21:34 +02:00
{
return m_data->hintTable.color( aspect );
2017-07-21 18:21:34 +02:00
}
2020-12-21 16:06:58 +01:00
void QskSkin::setMetric( QskAspect aspect, qreal metric )
2017-07-21 18:21:34 +02:00
{
m_data->hintTable.setMetric( aspect, metric );
2017-07-21 18:21:34 +02:00
}
2020-12-21 16:06:58 +01:00
qreal QskSkin::metric( QskAspect aspect ) const
2017-07-21 18:21:34 +02:00
{
return m_data->hintTable.metric( aspect );
2017-07-21 18:21:34 +02:00
}
2020-12-21 16:06:58 +01:00
void QskSkin::setStrutSize( QskAspect aspect, qreal width, qreal height )
{
setStrutSize( aspect, QSizeF( width, height ) );
}
2020-12-21 16:06:58 +01:00
void QskSkin::setStrutSize( QskAspect aspect, const QSizeF& strut )
{
m_data->hintTable.setStrutSize( aspect, strut );
}
2020-12-21 16:06:58 +01:00
QSizeF QskSkin::strutSize( QskAspect aspect ) const
{
return m_data->hintTable.strutSize( aspect );
}
2020-12-21 16:06:58 +01:00
void QskSkin::setMargin( QskAspect aspect, const QskMargins& margins )
{
m_data->hintTable.setMargin( aspect, margins );
}
2020-12-21 16:06:58 +01:00
void QskSkin::setMargin( QskAspect aspect,
2020-12-17 16:12:18 +01:00
qreal left, qreal top, qreal right, qreal bottom )
2020-12-21 16:06:58 +01:00
{
2020-12-17 16:12:18 +01:00
const QskMargins margins( left, top, right, bottom );
m_data->hintTable.setMargin( aspect, margins );
}
2020-12-21 16:06:58 +01:00
QskMargins QskSkin::margin( QskAspect aspect ) const
{
return m_data->hintTable.margin( aspect );
}
2020-12-21 16:06:58 +01:00
void QskSkin::setPadding( QskAspect aspect, const QskMargins& padding )
{
m_data->hintTable.setPadding( aspect, padding );
}
2020-12-21 16:06:58 +01:00
void QskSkin::setPadding( QskAspect aspect,
2020-12-17 16:12:18 +01:00
qreal left, qreal top, qreal right, qreal bottom )
2020-12-21 16:06:58 +01:00
{
2020-12-17 16:12:18 +01:00
const QskMargins padding( left, top, right, bottom );
m_data->hintTable.setPadding( aspect, padding );
}
2020-12-21 16:06:58 +01:00
QskMargins QskSkin::padding( QskAspect aspect ) const
{
return m_data->hintTable.padding( aspect );
}
2020-12-21 16:06:58 +01:00
void QskSkin::setSpacing( QskAspect aspect, qreal spacing )
{
m_data->hintTable.setSpacing( aspect, spacing );
}
2020-12-21 16:06:58 +01:00
qreal QskSkin::spacing( QskAspect aspect ) const
{
return m_data->hintTable.spacing( aspect );
}
2020-12-21 16:06:58 +01:00
void QskSkin::setGradient( QskAspect aspect, const QskGradient& gradient )
{
m_data->hintTable.setGradient( aspect, gradient );
}
2020-12-21 16:06:58 +01:00
QskGradient QskSkin::gradient( QskAspect aspect ) const
{
return m_data->hintTable.gradient( aspect );
}
2020-12-21 16:06:58 +01:00
void QskSkin::setBoxShape( QskAspect aspect,
2017-10-18 20:00:06 +02:00
qreal radius, Qt::SizeMode sizeMode )
{
2017-10-18 20:00:06 +02:00
m_data->hintTable.setBoxShape( aspect,
QskBoxShapeMetrics( radius, radius, radius, radius, sizeMode ) );
}
2020-12-21 16:06:58 +01:00
void QskSkin::setBoxShape( QskAspect aspect, qreal topLeft, qreal topRight,
2017-10-18 20:00:06 +02:00
qreal bottomLeft, qreal bottomRight, Qt::SizeMode sizeMode )
{
2018-03-22 11:20:13 +01:00
m_data->hintTable.setBoxShape( aspect,
2017-10-18 20:00:06 +02:00
QskBoxShapeMetrics( topLeft, topRight, bottomLeft, bottomRight, sizeMode ) );
}
2020-12-21 16:06:58 +01:00
void QskSkin::setBoxShape( QskAspect aspect, const QskBoxShapeMetrics& shape )
{
m_data->hintTable.setBoxShape( aspect, shape );
}
2020-12-21 16:06:58 +01:00
QskBoxShapeMetrics QskSkin::boxShape( QskAspect aspect ) const
{
return m_data->hintTable.boxShape( aspect );
}
2020-12-21 16:06:58 +01:00
void QskSkin::setBoxBorderMetrics( QskAspect aspect,
2017-10-18 20:00:06 +02:00
qreal left, qreal top, qreal right, qreal bottom, Qt::SizeMode sizeMode )
{
2018-03-22 11:20:13 +01:00
m_data->hintTable.setBoxBorder( aspect,
2017-10-18 20:00:06 +02:00
QskBoxBorderMetrics( left, top, right, bottom, sizeMode ) );
}
2020-12-21 16:06:58 +01:00
void QskSkin::setBoxBorderMetrics( QskAspect aspect,
2020-12-17 16:12:18 +01:00
qreal borderWidth, Qt::SizeMode sizeMode )
{
m_data->hintTable.setBoxBorder(
aspect, QskBoxBorderMetrics( borderWidth, sizeMode ) );
}
2017-10-18 20:00:06 +02:00
void QskSkin::setBoxBorderMetrics(
2020-12-21 16:06:58 +01:00
QskAspect aspect, const QskBoxBorderMetrics& border )
{
m_data->hintTable.setBoxBorder( aspect, border );
}
2020-12-21 16:06:58 +01:00
QskBoxBorderMetrics QskSkin::boxBorderMetrics( QskAspect aspect ) const
{
return m_data->hintTable.boxBorder( aspect );
}
2020-12-21 16:06:58 +01:00
void QskSkin::setBoxBorderColors( QskAspect aspect, const QskBoxBorderColors& colors )
{
m_data->hintTable.setBoxBorderColors( aspect, colors );
2018-03-22 11:20:13 +01:00
}
2020-12-21 16:06:58 +01:00
QskBoxBorderColors QskSkin::boxBorderColors( QskAspect aspect ) const
{
return m_data->hintTable.boxBorderColors( aspect );
}
2020-12-21 16:06:58 +01:00
void QskSkin::setFontRole( QskAspect aspect, int fontRole )
{
m_data->hintTable.setFontRole( aspect, fontRole );
}
2020-12-21 16:06:58 +01:00
void QskSkin::setGraphicRole( QskAspect aspect, int graphicRole )
{
m_data->hintTable.setGraphicRole( aspect, graphicRole );
}
2020-12-21 16:06:58 +01:00
void QskSkin::setAnimation( QskAspect aspect, QskAnimationHint animation )
2017-07-21 18:21:34 +02:00
{
m_data->hintTable.setAnimation( aspect, animation );
2017-07-21 18:21:34 +02:00
}
2020-12-21 16:06:58 +01:00
QskAnimationHint QskSkin::animation( QskAspect aspect ) const
2017-07-21 18:21:34 +02:00
{
return m_data->hintTable.animation( aspect );
2017-07-21 18:21:34 +02:00
}
2020-12-21 16:06:58 +01:00
void QskSkin::setAlignment( QskAspect aspect, Qt::Alignment alignment )
{
m_data->hintTable.setAlignment( aspect, alignment );
}
2020-12-21 16:06:58 +01:00
Qt::Alignment QskSkin::alignment( QskAspect aspect ) const
{
return m_data->hintTable.alignment( aspect );
}
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;
if ( entry.skinlet != nullptr )
{
delete entry.skinlet;
entry.skinlet = nullptr;
}
}
}
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;
}
QskSkinHintTable& QskSkin::skinHintTable()
{
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;
}
2017-07-21 18:21:34 +02:00
QskSkinlet* QskSkin::skinlet( const QskSkinnable* skinnable )
{
for ( auto metaObject = skinnable->metaObject();
metaObject != nullptr; metaObject = metaObject->superClass() )
{
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;
}
}
static QskSkinlet defaultSkinlet;
return &defaultSkinlet;
}
void QskSkin::resetColors( const QColor& )
{
}
#include "moc_QskSkin.cpp"