Fluent2 skin reactivated
This commit is contained in:
parent
5cf3f09364
commit
e5e2921bba
File diff suppressed because it is too large
Load Diff
|
@ -18,9 +18,12 @@ class QSK_FLUENT2_EXPORT QskFluent2Skin : public QskSkin
|
||||||
using Inherited = QskSkin;
|
using Inherited = QskSkin;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QskFluent2Skin( const QskFluent2Theme&, QObject* parent = nullptr );
|
QskFluent2Skin( QObject* parent = nullptr );
|
||||||
~QskFluent2Skin() override;
|
~QskFluent2Skin() override;
|
||||||
|
|
||||||
|
void addTheme( QskAspect::Section, const QskFluent2Theme& );
|
||||||
|
void setup();
|
||||||
|
|
||||||
enum GraphicRole
|
enum GraphicRole
|
||||||
{
|
{
|
||||||
GraphicRoleFillColorTextDisabled,
|
GraphicRoleFillColorTextDisabled,
|
||||||
|
|
|
@ -7,8 +7,16 @@
|
||||||
#include "QskFluent2Skin.h"
|
#include "QskFluent2Skin.h"
|
||||||
#include "QskFluent2Theme.h"
|
#include "QskFluent2Theme.h"
|
||||||
|
|
||||||
static const QString fluent2LightSkinName = QStringLiteral( "Fluent2 Light" );
|
static const QString nameLight = QStringLiteral( "Fluent2 Light" );
|
||||||
static const QString fluent2DarkSkinName = QStringLiteral( "Fluent2 Dark" );
|
static const QString nameDark = QStringLiteral( "Fluent2 Dark" );
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
inline constexpr QRgb rgbGray( int value )
|
||||||
|
{
|
||||||
|
return qRgba( value, value, value, 255 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QskFluent2SkinFactory::QskFluent2SkinFactory( QObject* parent )
|
QskFluent2SkinFactory::QskFluent2SkinFactory( QObject* parent )
|
||||||
: QskSkinFactory( parent )
|
: QskSkinFactory( parent )
|
||||||
|
@ -21,23 +29,71 @@ QskFluent2SkinFactory::~QskFluent2SkinFactory()
|
||||||
|
|
||||||
QStringList QskFluent2SkinFactory::skinNames() const
|
QStringList QskFluent2SkinFactory::skinNames() const
|
||||||
{
|
{
|
||||||
return { fluent2LightSkinName, fluent2DarkSkinName };
|
return { nameLight, nameDark };
|
||||||
}
|
}
|
||||||
|
|
||||||
QskSkin* QskFluent2SkinFactory::createSkin( const QString& skinName )
|
QskSkin* QskFluent2SkinFactory::createSkin( const QString& skinName )
|
||||||
{
|
{
|
||||||
if ( QString::compare( skinName, fluent2LightSkinName, Qt::CaseInsensitive ) == 0 )
|
QskSkin::ColorScheme colorScheme;
|
||||||
|
|
||||||
|
if ( QString::compare( skinName, nameLight, Qt::CaseInsensitive ) == 0 )
|
||||||
{
|
{
|
||||||
QskFluent2Theme theme( QskSkin::LightScheme );
|
colorScheme = QskSkin::LightScheme;
|
||||||
return new QskFluent2Skin( theme );
|
|
||||||
}
|
}
|
||||||
else if ( QString::compare( skinName, fluent2DarkSkinName, Qt::CaseInsensitive ) == 0 )
|
else if ( QString::compare( skinName, nameDark, Qt::CaseInsensitive ) == 0 )
|
||||||
{
|
{
|
||||||
QskFluent2Theme theme( QskSkin::DarkScheme );
|
colorScheme = QskSkin::DarkScheme;
|
||||||
return new QskFluent2Skin( theme );
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
struct
|
||||||
|
{
|
||||||
|
QskSkin::ColorScheme scheme;
|
||||||
|
QskFluent2Theme::BaseColors baseColors;
|
||||||
|
QskFluent2Theme::AccentColors accentColors;
|
||||||
|
|
||||||
|
QskFluent2Theme theme() const { return { scheme, baseColors, accentColors }; }
|
||||||
|
} colors[2];
|
||||||
|
|
||||||
|
switch( colorScheme )
|
||||||
|
{
|
||||||
|
case QskSkin::LightScheme:
|
||||||
|
{
|
||||||
|
colors[0].scheme = colorScheme;
|
||||||
|
colors[0].baseColors = { rgbGray( 243 ), rgbGray( 249 ), rgbGray( 238 ) };
|
||||||
|
colors[0].accentColors = { 0xff0078d4, 0xff005eb7, 0xff003d92, 0xff001968 };
|
||||||
|
|
||||||
|
colors[1].scheme = colorScheme;
|
||||||
|
colors[1].baseColors = { rgbGray( 249 ), rgbGray( 249 ), rgbGray( 238 ) };
|
||||||
|
colors[1].accentColors = colors[0].accentColors;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QskSkin::DarkScheme:
|
||||||
|
{
|
||||||
|
colors[0].scheme = colorScheme;
|
||||||
|
colors[0].baseColors = { rgbGray( 32 ), rgbGray( 40 ), rgbGray( 28 ) };
|
||||||
|
colors[0].accentColors = { 0xff0078d4, 0xff0093f9, 0xff60ccfe, 0xff98ecfe };
|
||||||
|
|
||||||
|
colors[1].scheme = colorScheme;
|
||||||
|
colors[1].baseColors = { rgbGray( 40 ), rgbGray( 44 ), rgbGray( 28 ) };
|
||||||
|
colors[1].accentColors = colors[0].accentColors;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto skin = new QskFluent2Skin();
|
||||||
|
|
||||||
|
skin->addTheme( QskAspect::Body, colors[0].theme() );
|
||||||
|
skin->addTheme( QskAspect::Header, colors[1].theme() );
|
||||||
|
skin->addTheme( QskAspect::Footer, colors[1].theme() );
|
||||||
|
|
||||||
|
return skin;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "moc_QskFluent2SkinFactory.cpp"
|
#include "moc_QskFluent2SkinFactory.cpp"
|
||||||
|
|
|
@ -14,27 +14,25 @@ namespace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QskFluent2Theme::QskFluent2Theme( QskSkin::ColorScheme colorScheme )
|
|
||||||
: QskFluent2Theme( colorScheme,
|
|
||||||
{ // default Fluent accent colors:
|
|
||||||
0xff98ecfe,
|
|
||||||
0xff60ccfe,
|
|
||||||
0xff0093f9,
|
|
||||||
0xff0078d4,
|
|
||||||
0xff005eb7,
|
|
||||||
0xff003d92,
|
|
||||||
0xff001968
|
|
||||||
} )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
QskFluent2Theme::QskFluent2Theme( QskSkin::ColorScheme colorScheme,
|
QskFluent2Theme::QskFluent2Theme( QskSkin::ColorScheme colorScheme,
|
||||||
const std::array< QRgb, NumAccentColors >& accentColors )
|
const BaseColors& baseColors, const AccentColors& accentColors )
|
||||||
{
|
{
|
||||||
using namespace QskRgb;
|
using namespace QskRgb;
|
||||||
|
|
||||||
|
{
|
||||||
|
auto& colors = palette.background;
|
||||||
|
|
||||||
|
colors.solid.base = baseColors.primary;
|
||||||
|
colors.solid.secondary = baseColors.secondary;
|
||||||
|
colors.solid.tertiary = baseColors.tertiary;
|
||||||
|
}
|
||||||
|
|
||||||
if( colorScheme != QskSkin::DarkScheme )
|
if( colorScheme != QskSkin::DarkScheme )
|
||||||
{
|
{
|
||||||
|
{
|
||||||
|
palette.background.solid.quaternary = rgbGray( 255 );
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto& colors = palette.fillColor;
|
auto& colors = palette.fillColor;
|
||||||
|
|
||||||
|
@ -43,9 +41,10 @@ QskFluent2Theme::QskFluent2Theme( QskSkin::ColorScheme colorScheme,
|
||||||
colors.text.tertiary = rgbGray( 0, 0.4458 );
|
colors.text.tertiary = rgbGray( 0, 0.4458 );
|
||||||
colors.text.disabled = rgbGray( 0, 0.3614 );
|
colors.text.disabled = rgbGray( 0, 0.3614 );
|
||||||
|
|
||||||
colors.accentText.primary = accentColors[ AccentDark2 ];
|
colors.accentText.primary = accentColors.tertiary;
|
||||||
colors.accentText.secondary = accentColors[ AccentDark3 ];
|
colors.accentText.secondary = accentColors.quaternary;
|
||||||
colors.accentText.tertiary = accentColors[ AccentDark1 ];
|
colors.accentText.tertiary = accentColors.secondary;
|
||||||
|
|
||||||
colors.accentText.disabled = rgbGray( 0, 0.3614 );
|
colors.accentText.disabled = rgbGray( 0, 0.3614 );
|
||||||
|
|
||||||
colors.textOnAccent.primary = rgbGray( 255 );
|
colors.textOnAccent.primary = rgbGray( 255 );
|
||||||
|
@ -73,13 +72,34 @@ QskFluent2Theme::QskFluent2Theme( QskSkin::ColorScheme colorScheme,
|
||||||
colors.controlAlt.quaternary = rgbGray( 0, 0.0924 );
|
colors.controlAlt.quaternary = rgbGray( 0, 0.0924 );
|
||||||
colors.controlAlt.disabled = Qt::transparent;
|
colors.controlAlt.disabled = Qt::transparent;
|
||||||
|
|
||||||
colors.accent.defaultColor = accentColors[ AccentDark1 ];
|
colors.accent.defaultColor = accentColors.secondary;
|
||||||
colors.accent.secondary = toTransparentF( accentColors[ AccentDark1 ], 0.90 );
|
colors.accent.secondary = toTransparentF( accentColors.secondary, 0.90 );
|
||||||
colors.accent.tertiary = toTransparentF( accentColors[ AccentDark1 ], 0.80 );
|
colors.accent.tertiary = toTransparentF( accentColors.secondary, 0.80 );
|
||||||
colors.accent.disabled = rgbGray( 0, 0.2169 );
|
colors.accent.disabled = rgbGray( 0, 0.2169 );
|
||||||
colors.accent.selectedTextBackground = accentColors[ AccentBase ];
|
colors.accent.selectedTextBackground = accentColors.primary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
{
|
||||||
|
// system colors
|
||||||
|
|
||||||
|
critical = 0xffc42b1c;
|
||||||
|
success = 0xff0f7b0f;
|
||||||
|
attention = 0xff005fb7;
|
||||||
|
caution = 0xff9d5d00;
|
||||||
|
attentionBackground = rgbGray( 246, 0.50 );
|
||||||
|
successBackground = 0xffdff6dd;
|
||||||
|
cautionBackground = 0xfffff4ce;
|
||||||
|
criticalBackground = 0xfffde7e9;
|
||||||
|
neutral = rgbGray( 0, 0.4458 );
|
||||||
|
neutralBackground = rgbGray( 0, 0.0241 );
|
||||||
|
|
||||||
|
solidNeutral = rgbGray( 138 );
|
||||||
|
solidAttentionBackground = rgbGray( 247 );
|
||||||
|
solidNeutralBackground = rgbGray( 243 );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
{
|
{
|
||||||
auto& colors = palette.elevation;
|
auto& colors = palette.elevation;
|
||||||
|
|
||||||
|
@ -118,30 +138,23 @@ QskFluent2Theme::QskFluent2Theme( QskSkin::ColorScheme colorScheme,
|
||||||
{
|
{
|
||||||
auto& colors = palette.background;
|
auto& colors = palette.background;
|
||||||
|
|
||||||
colors.card.defaultColor = rgbGray( 255, 0.70 );
|
|
||||||
colors.card.secondary = rgbGray( 246, 0.50 );
|
|
||||||
colors.card.tertiary = rgbGray( 255 );
|
|
||||||
|
|
||||||
colors.overlay.defaultColor = rgbGray( 0, 0.30 );
|
colors.overlay.defaultColor = rgbGray( 0, 0.30 );
|
||||||
colors.layer.alt = rgbGray( 255 );
|
colors.layer.alt = rgbGray( 255 );
|
||||||
colors.flyout.defaultColor = rgbGray( 252, 0.85 );
|
colors.flyout.defaultColor = rgbGray( 252, 0.85 );
|
||||||
|
|
||||||
colors.solid.base = rgbGray( 243 );
|
|
||||||
colors.solid.secondary = rgbGray( 238 );
|
|
||||||
colors.solid.tertiary = rgbGray( 249 );
|
|
||||||
colors.solid.quaternary = rgbGray( 255 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shadow:
|
// Shadow:
|
||||||
|
|
||||||
shadow.cardRest = { QskShadowMetrics( 0, 4, QPointF( 0, 2 ) ), rgbGray( 0, 0.04 ) };
|
|
||||||
shadow.cardHover = { QskShadowMetrics( 0, 4, QPointF( 0, 2 ) ), rgbGray( 0, 0.10 ) };
|
|
||||||
shadow.flyout = { QskShadowMetrics( 0, 16, QPointF( 0, 8 ) ), rgbGray( 0, 0.14 ) };
|
shadow.flyout = { QskShadowMetrics( 0, 16, QPointF( 0, 8 ) ), rgbGray( 0, 0.14 ) };
|
||||||
// ### should actually be drawn twice with different values:
|
// ### should actually be drawn twice with different values:
|
||||||
shadow.dialog = { QskShadowMetrics( 0, 21, QPointF( 0, 2 ) ), rgbGray( 0, 0.1474 ) };
|
shadow.dialog = { QskShadowMetrics( 0, 21, QPointF( 0, 2 ) ), rgbGray( 0, 0.1474 ) };
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
{
|
||||||
|
palette.background.solid.quaternary = rgbGray( 44 );
|
||||||
|
}
|
||||||
{
|
{
|
||||||
auto& colors = palette.fillColor;
|
auto& colors = palette.fillColor;
|
||||||
|
|
||||||
|
@ -150,9 +163,9 @@ QskFluent2Theme::QskFluent2Theme( QskSkin::ColorScheme colorScheme,
|
||||||
colors.text.tertiary = rgbGray( 255, 0.5442 );
|
colors.text.tertiary = rgbGray( 255, 0.5442 );
|
||||||
colors.text.disabled = rgbGray( 255, 0.3628 );
|
colors.text.disabled = rgbGray( 255, 0.3628 );
|
||||||
|
|
||||||
colors.accentText.primary = accentColors[ AccentLight3 ];
|
colors.accentText.primary = accentColors.quaternary;
|
||||||
colors.accentText.secondary = accentColors[ AccentLight3 ];
|
colors.accentText.secondary = accentColors.quaternary;
|
||||||
colors.accentText.tertiary = accentColors[ AccentLight2 ];
|
colors.accentText.tertiary = accentColors.tertiary;
|
||||||
colors.accentText.disabled = rgbGray( 255, 0.3628 );
|
colors.accentText.disabled = rgbGray( 255, 0.3628 );
|
||||||
|
|
||||||
colors.textOnAccent.primary = rgbGray( 0 );
|
colors.textOnAccent.primary = rgbGray( 0 );
|
||||||
|
@ -180,13 +193,33 @@ QskFluent2Theme::QskFluent2Theme( QskSkin::ColorScheme colorScheme,
|
||||||
colors.controlAlt.quaternary = rgbGray( 255, 0.0698 );
|
colors.controlAlt.quaternary = rgbGray( 255, 0.0698 );
|
||||||
colors.controlAlt.disabled = Qt::transparent;
|
colors.controlAlt.disabled = Qt::transparent;
|
||||||
|
|
||||||
colors.accent.defaultColor = accentColors[ AccentLight2 ];
|
colors.accent.defaultColor = accentColors.tertiary;
|
||||||
colors.accent.secondary = toTransparentF( accentColors[ AccentLight2 ], 0.90 );
|
colors.accent.secondary = toTransparentF( accentColors.tertiary, 0.90 );
|
||||||
colors.accent.tertiary = toTransparentF( accentColors[ AccentLight2 ], 0.80 );
|
colors.accent.tertiary = toTransparentF( accentColors.tertiary, 0.80 );
|
||||||
colors.accent.disabled = rgbGray( 255, 0.1581 );
|
colors.accent.disabled = rgbGray( 255, 0.1581 );
|
||||||
colors.accent.selectedTextBackground = accentColors[ AccentBase ];
|
colors.accent.selectedTextBackground = accentColors.primary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
{
|
||||||
|
// system colors
|
||||||
|
|
||||||
|
critical = 0xffff99a4;
|
||||||
|
success = 0xff6ccb5f;
|
||||||
|
attention = 0xff60cdff;
|
||||||
|
caution = 0xfffce100;
|
||||||
|
attentionBackground = rgbGray( 255, 0.0326 );
|
||||||
|
successBackground = 0xff393d1b;
|
||||||
|
cautionBackground = 0xff433519;
|
||||||
|
criticalBackground = 0xff442726;
|
||||||
|
neutral = rgbGray( 255, 0.5442 );
|
||||||
|
neutralBackground = rgbGray( 255, 0.0326 );
|
||||||
|
solidNeutral = rgbGray( 157 );
|
||||||
|
solidAttentionBackground = rgbGray( 46 );
|
||||||
|
solidNeutralBackground = rgbGray( 46 );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
{
|
{
|
||||||
auto& colors = palette.elevation;
|
auto& colors = palette.elevation;
|
||||||
|
|
||||||
|
@ -227,24 +260,13 @@ QskFluent2Theme::QskFluent2Theme( QskSkin::ColorScheme colorScheme,
|
||||||
{
|
{
|
||||||
auto& colors = palette.background;
|
auto& colors = palette.background;
|
||||||
|
|
||||||
colors.card.defaultColor = rgbGray( 255, 0.0512 );
|
|
||||||
colors.card.secondary = rgbGray( 255, 0.0326 );
|
|
||||||
colors.card.tertiary = rgbGray( 255 ); // not set in Figma
|
|
||||||
|
|
||||||
colors.overlay.defaultColor = rgbGray( 0, 0.30 );
|
colors.overlay.defaultColor = rgbGray( 0, 0.30 );
|
||||||
colors.layer.alt = rgbGray( 255, 0.0538 );
|
colors.layer.alt = rgbGray( 255, 0.0538 );
|
||||||
colors.flyout.defaultColor = rgbGray( 44, 0.96 );
|
colors.flyout.defaultColor = rgbGray( 44, 0.96 );
|
||||||
|
|
||||||
colors.solid.base = rgbGray( 32 );
|
|
||||||
colors.solid.secondary = rgbGray( 28 );
|
|
||||||
colors.solid.tertiary = rgbGray( 40 );
|
|
||||||
colors.solid.quaternary = rgbGray( 44 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shadow:
|
// Shadow:
|
||||||
|
|
||||||
shadow.cardRest = { QskShadowMetrics( 0, 4, QPointF( 0, 2 ) ), rgbGray( 0, 0.13 ) };
|
|
||||||
shadow.cardHover = { QskShadowMetrics( 0, 4, QPointF( 0, 2 ) ), rgbGray( 0, 0.26 ) };
|
|
||||||
shadow.flyout = { QskShadowMetrics( 0, 16, QPointF( 0, 8 ) ), rgbGray( 0, 0.26 ) };
|
shadow.flyout = { QskShadowMetrics( 0, 16, QPointF( 0, 8 ) ), rgbGray( 0, 0.26 ) };
|
||||||
// ### should actually be drawn twice with different values:
|
// ### should actually be drawn twice with different values:
|
||||||
shadow.dialog = { QskShadowMetrics( 0, 21, QPointF( 0, 2 ) ), rgbGray( 0, 0.37 ) };
|
shadow.dialog = { QskShadowMetrics( 0, 21, QPointF( 0, 2 ) ), rgbGray( 0, 0.37 ) };
|
||||||
|
|
|
@ -17,21 +17,23 @@
|
||||||
class QSK_FLUENT2_EXPORT QskFluent2Theme
|
class QSK_FLUENT2_EXPORT QskFluent2Theme
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum AccentColors
|
struct BaseColors
|
||||||
{
|
{
|
||||||
AccentLight3,
|
QRgb primary;
|
||||||
AccentLight2,
|
QRgb secondary;
|
||||||
AccentLight1,
|
QRgb tertiary;
|
||||||
AccentBase,
|
|
||||||
AccentDark1,
|
|
||||||
AccentDark2,
|
|
||||||
AccentDark3,
|
|
||||||
|
|
||||||
NumAccentColors
|
|
||||||
};
|
};
|
||||||
|
|
||||||
QskFluent2Theme( QskSkin::ColorScheme );
|
struct AccentColors
|
||||||
QskFluent2Theme( QskSkin::ColorScheme, const std::array< QRgb, NumAccentColors >& );
|
{
|
||||||
|
QRgb primary;
|
||||||
|
QRgb secondary;
|
||||||
|
QRgb tertiary;
|
||||||
|
QRgb quaternary;
|
||||||
|
};
|
||||||
|
|
||||||
|
QskFluent2Theme( QskSkin::ColorScheme, const BaseColors& baseColors,
|
||||||
|
const AccentColors& accentColors );
|
||||||
|
|
||||||
typedef std::array< QRgb, 2 > BorderGradient;
|
typedef std::array< QRgb, 2 > BorderGradient;
|
||||||
|
|
||||||
|
@ -175,13 +177,6 @@ class QSK_FLUENT2_EXPORT QskFluent2Theme
|
||||||
|
|
||||||
struct Background
|
struct Background
|
||||||
{
|
{
|
||||||
struct
|
|
||||||
{
|
|
||||||
QRgb defaultColor;
|
|
||||||
QRgb secondary;
|
|
||||||
QRgb tertiary;
|
|
||||||
} card;
|
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
QRgb defaultColor;
|
QRgb defaultColor;
|
||||||
|
@ -222,8 +217,6 @@ class QSK_FLUENT2_EXPORT QskFluent2Theme
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
ShadowSettings cardRest;
|
|
||||||
ShadowSettings cardHover;
|
|
||||||
ShadowSettings flyout;
|
ShadowSettings flyout;
|
||||||
ShadowSettings dialog;
|
ShadowSettings dialog;
|
||||||
} shadow;
|
} shadow;
|
||||||
|
|
|
@ -90,10 +90,6 @@ namespace
|
||||||
const auto factoryData = pluginData.value( TokenData ).toObject();
|
const auto factoryData = pluginData.value( TokenData ).toObject();
|
||||||
|
|
||||||
m_factoryId = factoryData.value( TokenFactoryId ).toString().toLower();
|
m_factoryId = factoryData.value( TokenFactoryId ).toString().toLower();
|
||||||
#if 1
|
|
||||||
if ( m_factoryId == "fluent2factory" )
|
|
||||||
return false; // we need to solve a couple of problems first
|
|
||||||
#endif
|
|
||||||
if ( m_factoryId.isEmpty() )
|
if ( m_factoryId.isEmpty() )
|
||||||
{
|
{
|
||||||
// Creating a dummy factory id
|
// Creating a dummy factory id
|
||||||
|
|
Loading…
Reference in New Issue