2168 lines
71 KiB
C++
2168 lines
71 KiB
C++
/******************************************************************************
|
|
* QSkinny - Copyright (C) The authors
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*****************************************************************************/
|
|
|
|
/*
|
|
Definitions ( where possible ) taken from
|
|
https://www.figma.com/file/NAWMapFlXnoOb86Q2H5GKr/Windows-UI-(Community)
|
|
*/
|
|
|
|
/*
|
|
TODO:
|
|
|
|
- we have a lot of lines with 1 pixels. Unfortunately OpenGL does some sort
|
|
of antialiasing, when a line is not a pixel position. On screens with high
|
|
resolution usually no probem, but f.e on mine ...
|
|
|
|
- QskCheckBox::Error is not properly supported
|
|
|
|
- Pressed state is missing
|
|
|
|
- QskComboBox
|
|
- QskPageIndicator
|
|
|
|
- Hovered state is missing
|
|
|
|
- QskPageIndicator
|
|
|
|
- QskListView
|
|
|
|
- Indicator subcontrol might be better than using the border of the selection box
|
|
- cell padding unclear
|
|
*/
|
|
|
|
/*
|
|
The palette is made of a couple of configurable base/accent colors and a
|
|
predefined set of semitransparent shades of gray. These grays are used
|
|
to create darkened/lightend colors from the configurable colors that can
|
|
be used for borders etc.
|
|
|
|
However borders need to be darkened for light base colors and lightened for
|
|
dark ones. So we actually have 2 different sets of grays for light/dark
|
|
colors schemes.
|
|
|
|
The main advantage of this concept is, that a working color schemes
|
|
can be defined by setting the accent/base colors only.
|
|
*/
|
|
#include "QskFluent2Skin.h"
|
|
#include "QskFluent2Theme.h"
|
|
#include "QskFluent2TextFieldSkinlet.h"
|
|
|
|
#include <QskSkinHintTableEditor.h>
|
|
|
|
#include <QskBox.h>
|
|
#include <QskCheckBox.h>
|
|
#include <QskComboBox.h>
|
|
#include <QskDialogButtonBox.h>
|
|
#include <QskDialogSubWindow.h>
|
|
#include <QskDrawer.h>
|
|
#include <QskFocusIndicator.h>
|
|
#include <QskGraphicLabel.h>
|
|
#include <QskListView.h>
|
|
#include <QskMenu.h>
|
|
#include <QskPageIndicator.h>
|
|
#include <QskPushButton.h>
|
|
#include <QskProgressBar.h>
|
|
#include <QskProgressRing.h>
|
|
#include <QskRadioBox.h>
|
|
#include <QskScrollView.h>
|
|
#include <QskSegmentedBar.h>
|
|
#include <QskSeparator.h>
|
|
#include <QskShadowMetrics.h>
|
|
#include <QskSlider.h>
|
|
#include <QskSpinBox.h>
|
|
#include <QskStandardSymbol.h>
|
|
#include <QskSubWindow.h>
|
|
#include <QskSwitchButton.h>
|
|
#include <QskSwitchButtonSkinlet.h>
|
|
#include <QskTabBar.h>
|
|
#include <QskTabButton.h>
|
|
#include <QskTabView.h>
|
|
#include <QskTextField.h>
|
|
#include <QskTextLabel.h>
|
|
#include <QskVirtualKeyboard.h>
|
|
|
|
#include <QskAnimationHint.h>
|
|
#include <QskAspect.h>
|
|
#include <QskBoxBorderColors.h>
|
|
#include <QskBoxBorderMetrics.h>
|
|
#include <QskBoxShapeMetrics.h>
|
|
#include <QskColorFilter.h>
|
|
#include <QskFunctions.h>
|
|
#include <QskGraphic.h>
|
|
#include <QskGraphicIO.h>
|
|
#include <QskMargins.h>
|
|
#include <QskRgbValue.h>
|
|
#include <QskFontRole.h>
|
|
|
|
#include <QskNamespace.h>
|
|
#include <QskPlatform.h>
|
|
|
|
#include <qguiapplication.h>
|
|
#include <qfontinfo.h>
|
|
|
|
static void qskFluent2InitResources()
|
|
{
|
|
Q_INIT_RESOURCE( QskFluent2Icons );
|
|
}
|
|
|
|
Q_CONSTRUCTOR_FUNCTION( qskFluent2InitResources )
|
|
|
|
namespace Fluent2
|
|
{
|
|
using F = QskFontRole;
|
|
|
|
/*
|
|
Fluent2/Windows font roles according to:
|
|
https://fluent2.microsoft.design/typography
|
|
*/
|
|
constexpr F Caption = { F::Caption, F::Normal };
|
|
|
|
constexpr F Body = { F::Body, F::Normal };
|
|
constexpr F BodyStrong = { F::Body, F::High };
|
|
constexpr F BodyStronger = { F::Body, F::VeryHigh };
|
|
|
|
constexpr F Subtitle = { F::Subtitle, F::Normal };
|
|
|
|
constexpr F Title = { F::Title, F::Normal };
|
|
|
|
constexpr F LargeTitle = { F::Headline, F::Normal };
|
|
constexpr F Display = { F::Display, F::Normal };
|
|
}
|
|
|
|
namespace
|
|
{
|
|
/*
|
|
mapping between px and logical coordinates
|
|
*/
|
|
inline constexpr double operator ""_px( long double value )
|
|
{
|
|
return static_cast< double >( value );
|
|
}
|
|
|
|
inline constexpr double operator ""_px( unsigned long long value )
|
|
{
|
|
return static_cast< double >( value );
|
|
}
|
|
|
|
inline constexpr QRgb rgbGray( int value, qreal opacity = 1.0 )
|
|
{
|
|
return qRgba( value, value, value, qRound( opacity * 255 ) );
|
|
}
|
|
|
|
/*
|
|
When application code is manipulating base colors manually the colors of
|
|
the borders will be lightened/darkened from it like expected - as long
|
|
as the application color matches the color scheme. Otherwise we end
|
|
up with lightened borders on light backgrounds or v.v.
|
|
|
|
To avoid this problem we could resolve the grays with the background
|
|
colors of the sections at definition time. This solves the problem with
|
|
applications using backgrounds from the "wrong" color scheme, but requires
|
|
more work for customizing controls hen using the "correct" scheme
|
|
( -> border colors need to be set as well ).
|
|
|
|
When enabling QSK_RESOLVE_COLORS a code path is enabled that is intended
|
|
to play with resolving the grays at definition time. But I'm not decided
|
|
if it is worth to make a feature from it. TODO ...
|
|
*/
|
|
|
|
#define QSK_RESOLVE_COLORS 0
|
|
|
|
#if QSK_RESOLVE_COLORS
|
|
|
|
inline constexpr QRgb rgbFlattened( QRgb foreground, QRgb background )
|
|
{
|
|
Q_ASSERT( qAlpha( background ) == 255 );
|
|
|
|
const auto r2 = qAlpha( foreground ) / 255.0;
|
|
const auto r1 = 1.0 - r2;
|
|
|
|
const auto r = qRound( r1 * qRed( background ) + r2 * qRed( foreground ) );
|
|
const auto g = qRound( r1 * qGreen( background ) + r2 * qGreen( foreground ) );
|
|
const auto b = qRound( r1 * qBlue( background ) + r2 * qBlue( foreground ) );
|
|
|
|
return qRgb( r, g, b );
|
|
}
|
|
|
|
inline constexpr QRgb rgbSolid( QRgb foreground, QRgb background )
|
|
{
|
|
/*
|
|
dummy method, so that we can compare the results with
|
|
or without resolving the foreground alpha value
|
|
*/
|
|
|
|
return rgbFlattened( foreground, background );
|
|
}
|
|
|
|
#else // !QSK_RESOLVE_COLORS
|
|
|
|
inline QRgb rgbFlattened( QRgb foreground, QRgb background )
|
|
{
|
|
const auto alpha = qAlpha( foreground ) / 255.0;
|
|
return QskRgb::interpolated( background, foreground, alpha );
|
|
}
|
|
|
|
inline constexpr QRgb rgbSolid( QRgb foreground, QRgb background )
|
|
{
|
|
Q_UNUSED( background );
|
|
return foreground;
|
|
}
|
|
|
|
#endif
|
|
|
|
class Editor : private QskSkinHintTableEditor
|
|
{
|
|
public:
|
|
Editor( QskSkinHintTable* table )
|
|
: QskSkinHintTableEditor( table )
|
|
{
|
|
}
|
|
|
|
void setupMetrics();
|
|
void setupColors( QskAspect::Section, const QskFluent2Theme& );
|
|
|
|
private:
|
|
void setupPopup( const QskFluent2Theme& );
|
|
void setupSubWindow( const QskFluent2Theme& );
|
|
void setupDialogSubWindow( const QskFluent2Theme& );
|
|
|
|
void setupBoxMetrics();
|
|
void setupBoxColors( QskAspect::Section, const QskFluent2Theme& );
|
|
|
|
void setupCheckBoxMetrics();
|
|
void setupCheckBoxColors( QskAspect::Section, const QskFluent2Theme& );
|
|
|
|
void setupComboBoxMetrics();
|
|
void setupComboBoxColors( QskAspect::Section, const QskFluent2Theme& );
|
|
|
|
void setupDialogButtonBoxMetrics();
|
|
void setupDialogButtonBoxColors( QskAspect::Section, const QskFluent2Theme& );
|
|
|
|
void setupDrawerMetrics();
|
|
void setupDrawerColors( QskAspect::Section, const QskFluent2Theme& );
|
|
|
|
void setupFocusIndicatorMetrics();
|
|
void setupFocusIndicatorColors( QskAspect::Section, const QskFluent2Theme& );
|
|
|
|
void setupGraphicLabelMetrics();
|
|
void setupGraphicLabelColors( QskAspect::Section, const QskFluent2Theme& );
|
|
|
|
void setupListViewMetrics();
|
|
void setupListViewColors( QskAspect::Section, const QskFluent2Theme& );
|
|
|
|
void setupMenuMetrics();
|
|
void setupMenuColors( QskAspect::Section, const QskFluent2Theme& );
|
|
|
|
void setupPageIndicatorMetrics();
|
|
void setupPageIndicatorColors( QskAspect::Section, const QskFluent2Theme& );
|
|
|
|
void setupProgressBarMetrics();
|
|
void setupProgressBarColors( QskAspect::Section, const QskFluent2Theme& );
|
|
|
|
void setupProgressRingMetrics();
|
|
void setupProgressRingColors( QskAspect::Section, const QskFluent2Theme& );
|
|
|
|
void setupPushButtonMetrics();
|
|
void setupPushButtonColors( QskAspect::Section, const QskFluent2Theme& );
|
|
|
|
void setupRadioBoxMetrics();
|
|
void setupRadioBoxColors( QskAspect::Section, const QskFluent2Theme& );
|
|
|
|
void setupScrollViewMetrics();
|
|
void setupScrollViewColors( QskAspect::Section, const QskFluent2Theme& );
|
|
|
|
void setupSegmentedBarMetrics();
|
|
void setupSegmentedBarColors( QskAspect::Section, const QskFluent2Theme& );
|
|
|
|
void setupSeparatorMetrics();
|
|
void setupSeparatorColors( QskAspect::Section, const QskFluent2Theme& );
|
|
|
|
void setupSliderMetrics();
|
|
void setupSliderColors( QskAspect::Section, const QskFluent2Theme& );
|
|
|
|
void setupSpinBoxMetrics();
|
|
void setupSpinBoxColors( QskAspect::Section, const QskFluent2Theme& );
|
|
|
|
void setupSwitchButtonMetrics();
|
|
void setupSwitchButtonColors( QskAspect::Section, const QskFluent2Theme& );
|
|
|
|
void setupTabButtonMetrics();
|
|
void setupTabButtonColors( QskAspect::Section, const QskFluent2Theme& );
|
|
|
|
void setupTabBarMetrics();
|
|
void setupTabBarColors( QskAspect::Section, const QskFluent2Theme& );
|
|
|
|
void setupTabViewMetrics();
|
|
void setupTabViewColors( QskAspect::Section, const QskFluent2Theme& );
|
|
|
|
void setupTextFieldMetrics();
|
|
void setupTextFieldColors( QskAspect::Section, const QskFluent2Theme& );
|
|
|
|
void setupTextLabelMetrics();
|
|
void setupTextLabelColors( QskAspect::Section, const QskFluent2Theme& );
|
|
|
|
void setupVirtualKeyboardMetrics();
|
|
void setupVirtualKeyboardColors( QskAspect::Section, const QskFluent2Theme& );
|
|
|
|
inline QskGraphic symbol( const char* name ) const
|
|
{
|
|
const QString path = QStringLiteral( ":fluent2/icons/qvg/" )
|
|
+ name + QStringLiteral( ".qvg" );
|
|
|
|
return QskGraphicIO::read( path );
|
|
}
|
|
|
|
inline void setBoxBorderGradient( QskAspect aspect,
|
|
QRgb border1, QRgb border2, QRgb baseColor )
|
|
{
|
|
border1 = rgbFlattened( border1, baseColor );
|
|
border2 = rgbFlattened( border2, baseColor );
|
|
|
|
setBoxBorderColors( aspect, { border1, border1, border1, border2 } );
|
|
}
|
|
|
|
inline void setBoxBorderGradient( QskAspect aspect,
|
|
const QskFluent2Theme::BorderGradient& gradient, QRgb baseColor )
|
|
{
|
|
setBoxBorderGradient( aspect, gradient[ 0 ], gradient[ 1 ], baseColor );
|
|
}
|
|
};
|
|
}
|
|
|
|
void Editor::setupMetrics()
|
|
{
|
|
setupBoxMetrics();
|
|
setupCheckBoxMetrics();
|
|
setupComboBoxMetrics();
|
|
setupDialogButtonBoxMetrics();
|
|
setupDrawerMetrics();
|
|
setupFocusIndicatorMetrics();
|
|
setupGraphicLabelMetrics();
|
|
setupListViewMetrics();
|
|
setupMenuMetrics();
|
|
setupPageIndicatorMetrics();
|
|
setupProgressBarMetrics();
|
|
setupProgressRingMetrics();
|
|
setupPushButtonMetrics();
|
|
setupRadioBoxMetrics();
|
|
setupScrollViewMetrics();
|
|
setupSegmentedBarMetrics();
|
|
setupSeparatorMetrics();
|
|
setupSliderMetrics();
|
|
setupSpinBoxMetrics();
|
|
setupSwitchButtonMetrics();
|
|
setupTabButtonMetrics();
|
|
setupTabBarMetrics();
|
|
setupTabViewMetrics();
|
|
setupTextFieldMetrics();
|
|
setupTextLabelMetrics();
|
|
setupVirtualKeyboardMetrics();
|
|
}
|
|
|
|
void Editor::setupColors( QskAspect::Section section, const QskFluent2Theme& theme )
|
|
{
|
|
if ( section == QskAspect::Body )
|
|
{
|
|
// TODO
|
|
setupPopup( theme );
|
|
setupSubWindow( theme );
|
|
setupDialogSubWindow( theme );
|
|
}
|
|
|
|
setupBoxColors( section, theme );
|
|
setupCheckBoxColors( section, theme );
|
|
setupComboBoxColors( section, theme );
|
|
setupDialogButtonBoxColors( section, theme );
|
|
setupDrawerColors( section, theme );
|
|
setupFocusIndicatorColors( section, theme );
|
|
setupGraphicLabelColors( section, theme );
|
|
setupGraphicLabelMetrics();
|
|
setupListViewColors( section, theme );
|
|
setupMenuColors( section, theme );
|
|
setupPageIndicatorColors( section, theme );
|
|
setupProgressBarColors( section, theme );
|
|
setupProgressRingColors( section, theme );
|
|
setupPushButtonColors( section, theme );
|
|
setupRadioBoxColors( section, theme );
|
|
setupScrollViewColors( section, theme );
|
|
setupSegmentedBarColors( section, theme );
|
|
setupSeparatorColors( section, theme );
|
|
setupSliderColors( section, theme );
|
|
setupSwitchButtonColors( section, theme );
|
|
setupSpinBoxColors( section, theme );
|
|
setupTabButtonColors( section, theme );
|
|
setupTabBarColors( section, theme );
|
|
setupTabViewColors( section, theme );
|
|
setupTextFieldColors( section, theme );
|
|
setupTextLabelColors( section, theme );
|
|
setupVirtualKeyboardColors( section, theme );
|
|
};
|
|
|
|
void Editor::setupBoxMetrics()
|
|
{
|
|
}
|
|
|
|
void Editor::setupBoxColors(
|
|
QskAspect::Section section, const QskFluent2Theme& theme )
|
|
{
|
|
setGradient( QskBox::Panel | section,
|
|
theme.palette.background.solid.base );
|
|
}
|
|
|
|
void Editor::setupCheckBoxMetrics()
|
|
{
|
|
using Q = QskCheckBox;
|
|
|
|
setStrutSize( Q::Panel, 126_px, 38_px );
|
|
setSpacing( Q::Panel, 8_px );
|
|
|
|
setStrutSize( Q::Box, { 20_px, 20_px } ); // 18 + 2*1 border
|
|
setBoxShape( Q::Box, 4_px ); // adapt to us taking the border into account
|
|
setBoxBorderMetrics( Q::Box, 1_px );
|
|
|
|
setFontRole( Q::Text, Fluent2::Body );
|
|
}
|
|
|
|
void Editor::setupCheckBoxColors(
|
|
QskAspect::Section section, const QskFluent2Theme& theme )
|
|
{
|
|
using Q = QskCheckBox;
|
|
using A = QskAspect;
|
|
|
|
const auto& pal = theme.palette;
|
|
|
|
const auto checkMark = symbol( "checkmark" );
|
|
|
|
for ( const auto state1 : { A::NoState, Q::Hovered, Q::Pressed, Q::Disabled } )
|
|
{
|
|
QRgb fillColor, borderColor, textColor;
|
|
|
|
for ( const auto state2 : { A::NoState, Q::Checked } )
|
|
{
|
|
const auto states = state1 | state2;
|
|
|
|
if ( states == A::NoState )
|
|
{
|
|
fillColor = pal.fillColor.controlAlt.secondary;
|
|
borderColor = pal.strokeColor.controlStrong.defaultColor;
|
|
textColor = pal.fillColor.text.primary;
|
|
}
|
|
else if ( states == Q::Hovered )
|
|
{
|
|
fillColor = pal.fillColor.controlAlt.tertiary;
|
|
borderColor = pal.strokeColor.controlStrong.defaultColor;
|
|
textColor = pal.fillColor.text.primary;
|
|
}
|
|
else if ( states == ( Q::Hovered | Q::Checked ) )
|
|
{
|
|
fillColor = pal.fillColor.accent.secondary;
|
|
borderColor = fillColor;
|
|
textColor = pal.fillColor.text.primary;
|
|
}
|
|
else if ( states == Q::Checked )
|
|
{
|
|
fillColor = pal.fillColor.accent.defaultColor;
|
|
borderColor = pal.fillColor.accent.defaultColor;
|
|
textColor = pal.fillColor.text.primary;
|
|
}
|
|
else if ( states == Q::Pressed )
|
|
{
|
|
fillColor = pal.fillColor.controlAlt.quaternary;
|
|
borderColor = pal.strokeColor.controlStrong.disabled;
|
|
textColor = pal.fillColor.text.primary;
|
|
}
|
|
else if ( states == ( Q::Pressed | Q::Checked ) )
|
|
{
|
|
fillColor = pal.fillColor.accent.tertiary;
|
|
borderColor = pal.fillColor.accent.tertiary;
|
|
textColor = pal.fillColor.text.primary;
|
|
|
|
setSymbol( Q::Indicator | states, checkMark );
|
|
}
|
|
else if ( states == Q::Disabled )
|
|
{
|
|
fillColor = pal.fillColor.controlAlt.disabled;
|
|
borderColor = pal.strokeColor.controlStrong.disabled;
|
|
textColor = pal.fillColor.text.disabled;
|
|
}
|
|
else if ( states == ( Q::Disabled | Q::Checked ) )
|
|
{
|
|
fillColor = pal.fillColor.accent.disabled;
|
|
borderColor = pal.fillColor.accent.disabled;
|
|
textColor = pal.fillColor.text.disabled;
|
|
}
|
|
|
|
/*
|
|
Support for QskCheckBox::Error is not properly defined.
|
|
Doing some basic definitions, so that we can at least
|
|
see the boxes with this state. TODO ...
|
|
*/
|
|
for ( const auto state3 : { A::NoState, Q::Error } )
|
|
{
|
|
const auto box = Q::Box | section | states | state3;
|
|
const auto text = Q::Text | section | states | state3;
|
|
const auto indicator = Q::Indicator | section | states | state3;
|
|
|
|
#if 1
|
|
if ( state3 == Q::Error && !( states & Q::Disabled ) )
|
|
{
|
|
borderColor = QskRgb::IndianRed;
|
|
if ( states & Q::Checked )
|
|
fillColor = QskRgb::DarkRed;
|
|
}
|
|
#endif
|
|
fillColor = rgbSolid( fillColor, pal.background.solid.base );
|
|
setGradient( box, fillColor );
|
|
|
|
borderColor = rgbSolid( borderColor, fillColor );
|
|
setBoxBorderColors( box, borderColor );
|
|
|
|
setColor( text, textColor );
|
|
|
|
if ( states & Q::Checked )
|
|
{
|
|
setGraphicRole( indicator, ( states & Q::Disabled )
|
|
? QskFluent2Skin::GraphicRoleFillColorTextOnAccentDisabled
|
|
: QskFluent2Skin::GraphicRoleFillColorTextOnAccentPrimary );
|
|
|
|
setSymbol( indicator, checkMark );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Editor::setupComboBoxMetrics()
|
|
{
|
|
using Q = QskComboBox;
|
|
|
|
setStrutSize( Q::Panel, { -1, 32_px } );
|
|
setBoxBorderMetrics( Q::Panel, 1_px );
|
|
setBoxShape( Q::Panel, 3_px );
|
|
setPadding( Q::Panel, { 11_px, 0_px, 11_px, 0_px } );
|
|
|
|
setStrutSize( Q::Icon, 12_px, 12_px );
|
|
setPadding( Q::Icon, { 0, 0, 8_px, 0 } );
|
|
|
|
setAlignment( Q::Text, Qt::AlignLeft | Qt::AlignVCenter );
|
|
setFontRole( Q::Text, Fluent2::Body );
|
|
|
|
setStrutSize( Q::StatusIndicator, 16_px, 16_px );
|
|
setSymbol( Q::StatusIndicator, symbol( "chevron_down" ) );
|
|
// setSymbol( Q::StatusIndicator | Q::PopupOpen, symbol( "chevron_up" ) );
|
|
|
|
// Using Focused (Pressed doesn't exist yet):
|
|
setBoxBorderMetrics( Q::Panel | Q::Focused, { 1_px, 1_px, 1_px, 2_px } );
|
|
}
|
|
|
|
void Editor::setupComboBoxColors(
|
|
QskAspect::Section section, const QskFluent2Theme& theme )
|
|
{
|
|
using Q = QskComboBox;
|
|
using W = QskFluent2Skin;
|
|
|
|
const auto& pal = theme.palette;
|
|
|
|
for ( const auto state :
|
|
{ QskAspect::NoState, Q::Hovered, Q::Focused, Q::Pressed, Q::Disabled } )
|
|
{
|
|
QRgb panelColor, borderColor1, borderColor2, textColor;
|
|
|
|
if ( state == QskAspect::NoState )
|
|
{
|
|
panelColor = pal.fillColor.control.defaultColor;
|
|
borderColor1 = pal.elevation.control.border[0];
|
|
borderColor2 = pal.elevation.control.border[1];
|
|
textColor = pal.fillColor.text.primary;
|
|
|
|
}
|
|
else if ( state == Q::Hovered )
|
|
{
|
|
panelColor = pal.fillColor.control.secondary;
|
|
borderColor1 = pal.elevation.textControl.border[0];
|
|
borderColor2 = pal.elevation.textControl.border[1];
|
|
textColor = pal.fillColor.text.primary;
|
|
}
|
|
else if ( state == Q::Focused )
|
|
{
|
|
panelColor = pal.fillColor.control.inputActive;
|
|
borderColor1 = pal.elevation.textControl.border[0];
|
|
borderColor2 = pal.fillColor.accent.defaultColor;
|
|
textColor = pal.fillColor.text.primary;
|
|
}
|
|
else if ( state == Q::Pressed )
|
|
{
|
|
panelColor = pal.fillColor.control.inputActive;
|
|
borderColor1 = pal.elevation.textControl.border[0];
|
|
borderColor2 = pal.fillColor.accent.defaultColor;
|
|
textColor = pal.fillColor.text.secondary;
|
|
}
|
|
else if ( state == Q::Disabled )
|
|
{
|
|
panelColor = pal.fillColor.control.disabled;
|
|
borderColor2 = borderColor1 = pal.strokeColor.control.defaultColor;
|
|
textColor = pal.fillColor.text.disabled;
|
|
}
|
|
|
|
const auto panel = Q::Panel | section | state;
|
|
const auto text = Q::Text | section | state;
|
|
const auto icon = Q::Icon | section | state;
|
|
const auto indicator = Q::StatusIndicator | section | state;
|
|
|
|
panelColor = rgbSolid( panelColor, pal.background.solid.base );
|
|
|
|
setGradient( panel, panelColor );
|
|
setBoxBorderGradient( panel, borderColor1, borderColor2, panelColor );
|
|
|
|
setColor( text, textColor );
|
|
|
|
if ( state == Q::Disabled )
|
|
{
|
|
setGraphicRole( icon, W::GraphicRoleFillColorTextDisabled );
|
|
setGraphicRole( indicator, W::GraphicRoleFillColorTextDisabled );
|
|
}
|
|
else if( state == Q::Pressed )
|
|
{
|
|
setGraphicRole( icon, W::GraphicRoleFillColorTextSecondary );
|
|
setGraphicRole( indicator, W::GraphicRoleFillColorTextSecondary );
|
|
}
|
|
else
|
|
{
|
|
setGraphicRole( icon, W::GraphicRoleFillColorTextPrimary );
|
|
setGraphicRole( indicator, W::GraphicRoleFillColorTextSecondary );
|
|
}
|
|
}
|
|
}
|
|
|
|
void Editor::setupDialogButtonBoxMetrics()
|
|
{
|
|
setPadding( QskDialogButtonBox::Panel, 20_px );
|
|
}
|
|
|
|
void Editor::setupDialogButtonBoxColors(
|
|
QskAspect::Section section, const QskFluent2Theme& theme )
|
|
{
|
|
setGradient( QskDialogButtonBox::Panel | section,
|
|
theme.palette.background.solid.base );
|
|
}
|
|
|
|
void Editor::setupDrawerMetrics()
|
|
{
|
|
using Q = QskDrawer;
|
|
using A = QskAspect;
|
|
|
|
setAnimation( Q::Panel | A::Position, 300, QEasingCurve::OutCubic );
|
|
}
|
|
|
|
void Editor::setupDrawerColors(
|
|
QskAspect::Section section, const QskFluent2Theme& theme )
|
|
{
|
|
setGradient( QskDrawer::Panel | section,
|
|
theme.palette.background.solid.base );
|
|
}
|
|
|
|
void Editor::setupFocusIndicatorMetrics()
|
|
{
|
|
using Q = QskFocusIndicator;
|
|
|
|
setBoxBorderMetrics( Q::Panel, 2_px );
|
|
setPadding( Q::Panel, 3_px );
|
|
setBoxShape( Q::Panel, 4_px );
|
|
}
|
|
|
|
void Editor::setupFocusIndicatorColors(
|
|
QskAspect::Section section, const QskFluent2Theme& theme )
|
|
{
|
|
using Q = QskFocusIndicator;
|
|
using A = QskAspect;
|
|
|
|
const auto& pal = theme.palette;
|
|
|
|
const auto aspect = Q::Panel | section;
|
|
const auto color = pal.strokeColor.focus.outer;
|
|
|
|
setBoxBorderColors( aspect, color );
|
|
setBoxBorderColors( aspect | Q::Disabled, QskRgb::toTransparent( color, 0 ) );
|
|
|
|
setAnimation( Q::Panel | A::Color, 200 );
|
|
setAnimation( Q::Panel | A::Color | Q::Disabled, 500 );
|
|
}
|
|
|
|
void Editor::setupListViewMetrics()
|
|
{
|
|
using Q = QskListView;
|
|
using A = QskAspect;
|
|
|
|
for ( auto state : { A::NoState, Q::Hovered, Q::Pressed } )
|
|
setBoxBorderMetrics( Q::Cell | state | Q::Selected, { 3_px, 0, 0, 0 } );
|
|
#if 1
|
|
// taken from M3 - what are the actual values, TODO ...
|
|
setPadding( Q::Cell, { 16_px, 12_px, 16_px, 12_px } );
|
|
#endif
|
|
}
|
|
|
|
void Editor::setupListViewColors(
|
|
QskAspect::Section section, const QskFluent2Theme& theme )
|
|
{
|
|
using Q = QskListView;
|
|
using A = QskAspect;
|
|
|
|
const auto& pal = theme.palette;
|
|
|
|
for ( const auto state1 : { A::NoState, Q::Hovered, Q::Pressed, Q::Disabled } )
|
|
{
|
|
QRgb textColor, indicatorColor;
|
|
|
|
if ( state1 == Q::Disabled )
|
|
{
|
|
textColor = pal.fillColor.text.disabled;
|
|
indicatorColor = pal.fillColor.accent.disabled;
|
|
}
|
|
else if ( state1 == Q::Pressed )
|
|
{
|
|
textColor = pal.fillColor.text.secondary;
|
|
indicatorColor = pal.fillColor.accent.defaultColor;
|
|
}
|
|
else
|
|
{
|
|
textColor = pal.fillColor.text.primary;
|
|
indicatorColor = pal.fillColor.accent.defaultColor;
|
|
}
|
|
|
|
for ( const auto state2 : { A::NoState, Q::Selected } )
|
|
{
|
|
QRgb cellColor;
|
|
|
|
if ( state2 == A::NoState )
|
|
{
|
|
if ( state1 == Q::Hovered )
|
|
cellColor = pal.fillColor.subtle.secondary;
|
|
else if ( state1 == Q::Pressed )
|
|
cellColor = pal.fillColor.subtle.tertiary;
|
|
else
|
|
cellColor = Qt::transparent;
|
|
}
|
|
else
|
|
{
|
|
if ( state1 == Q::Hovered )
|
|
cellColor = pal.fillColor.subtle.tertiary;
|
|
else
|
|
cellColor = pal.fillColor.subtle.secondary;
|
|
}
|
|
|
|
const auto cell = Q::Cell | section | state1 | state2;
|
|
const auto text = Q::Text | section | state1 | state2;
|
|
|
|
setGradient( cell, cellColor );
|
|
|
|
{
|
|
/*
|
|
We are using a section of the left border to display a
|
|
bar indicating the selection. Maybe we should introduce a
|
|
subcontrol instead TODO ...
|
|
*/
|
|
const auto c1 = cellColor;
|
|
const auto c2 = indicatorColor;
|
|
|
|
const auto p1 = ( state1 == Q::Pressed ) ? 0.33 : 0.25;
|
|
const auto p2 = 1.0 - p1;
|
|
|
|
setBoxBorderColors( cell,
|
|
QskGradient( { { p1, c1 }, { p1, c2 }, { p2, c2 }, { p2, c1 } } ) );
|
|
}
|
|
|
|
setColor( text, textColor );
|
|
}
|
|
}
|
|
|
|
setAnimation( Q::Cell | A::Color, 100 );
|
|
setAnimation( Q::Text | A::Color, 100 );
|
|
}
|
|
|
|
void Editor::setupMenuMetrics()
|
|
{
|
|
using Q = QskMenu;
|
|
using A = QskAspect;
|
|
|
|
setPadding( Q::Panel, { 4_px, 6_px, 4_px, 6_px } );
|
|
setBoxBorderMetrics( Q::Panel, 1_px );
|
|
setBoxShape( Q::Panel, 7_px );
|
|
|
|
setPadding( Q::Segment, { 0, 10_px, 10_px, 10_px } );
|
|
setSpacing( Q::Segment, 15_px );
|
|
setBoxBorderMetrics( Q::Segment | Q::Selected, { 3_px, 0, 0, 0 } );
|
|
|
|
setFontRole( Q::Text, Fluent2::Body );
|
|
|
|
setStrutSize( Q::Icon, 12_px, 12_px );
|
|
setPadding( Q::Icon, { 8_px, 8_px, 0, 8_px } );
|
|
|
|
setAnimation( Q::Panel | A::Position, 100 );
|
|
}
|
|
|
|
void Editor::setupMenuColors(
|
|
QskAspect::Section section, const QskFluent2Theme& theme )
|
|
{
|
|
Q_UNUSED( section );
|
|
|
|
using Q = QskMenu;
|
|
|
|
#if 1
|
|
setShadowMetrics( Q::Panel, theme.shadow.flyout.metrics );
|
|
#endif
|
|
|
|
const auto& pal = theme.palette;
|
|
|
|
setBoxBorderColors( Q::Panel, pal.strokeColor.surface.flyout );
|
|
setGradient( Q::Panel, pal.background.flyout.defaultColor );
|
|
setShadowColor( Q::Panel, theme.shadow.flyout.color );
|
|
|
|
setGradient( Q::Segment | Q::Hovered, pal.fillColor.subtle.secondary );
|
|
setGradient( Q::Segment | Q::Selected | Q::Pressed, pal.fillColor.subtle.tertiary );
|
|
|
|
setGradient( Q::Segment | Q::Selected, pal.fillColor.subtle.secondary );
|
|
|
|
/*
|
|
We are using a section of the left border to display a
|
|
bar indicating the selection. Maybe we should introduce a
|
|
subcontrol instead TODO ...
|
|
*/
|
|
const auto c1 = pal.fillColor.subtle.secondary;
|
|
const auto c2 = pal.fillColor.accent.defaultColor;
|
|
|
|
setBoxBorderColors( Q::Segment | Q::Selected,
|
|
QskGradient( { { 0.25, c1 }, { 0.25, c2 }, { 0.75, c2 }, { 0.75, c1 } } ) );
|
|
|
|
setBoxBorderColors( Q::Segment | Q::Selected | Q::Pressed,
|
|
QskGradient( { { 0.33, c1 }, { 0.33, c2 }, { 0.67, c2 }, { 0.67, c1 } } ) );
|
|
|
|
setColor( Q::Text, pal.fillColor.text.primary );
|
|
setColor( Q::Text | Q::Selected | Q::Pressed, pal.fillColor.text.secondary );
|
|
|
|
setGraphicRole( Q::Icon, QskFluent2Skin::GraphicRoleFillColorTextPrimary );
|
|
setGraphicRole( Q::Icon | Q::Selected | Q::Pressed,
|
|
QskFluent2Skin::GraphicRoleFillColorTextSecondary );
|
|
}
|
|
|
|
void Editor::setupPageIndicatorMetrics()
|
|
{
|
|
using Q = QskPageIndicator;
|
|
using A = QskAspect;
|
|
|
|
setPadding( Q::Panel, 5_px );
|
|
setSpacing( Q::Panel, 6_px );
|
|
|
|
// circles, without border
|
|
|
|
setBoxShape( Q::Bullet, 100, Qt::RelativeSize );
|
|
setBoxBorderMetrics( Q::Bullet, 0 );
|
|
|
|
/*
|
|
Pressed/Hovered are not yet implemented.
|
|
Sizes would be:
|
|
|
|
- Q::Pressed : 3
|
|
- Q::Pressed | Q::Selected : 5
|
|
- Q::Hovered : 5
|
|
- Q::Hovered | Q::Selected : 7
|
|
*/
|
|
|
|
setStrutSize( Q::Bullet, 6_px, 6_px );
|
|
|
|
/*
|
|
Using the margin to adjust sizes is a weired type of implementation.
|
|
Needs to be changed TODO ...
|
|
*/
|
|
for ( auto state : { A::NoState, Q::Disabled } )
|
|
{
|
|
setMargin( Q::Bullet | state | Q::Selected, 0 );
|
|
setMargin( Q::Bullet | state, 1_px );
|
|
}
|
|
}
|
|
|
|
void Editor::setupPageIndicatorColors(
|
|
QskAspect::Section section, const QskFluent2Theme& theme )
|
|
{
|
|
using Q = QskPageIndicator;
|
|
using A = QskAspect;
|
|
|
|
const auto& pal = theme.palette;
|
|
|
|
setGradient( Q::Panel, QskGradient() );
|
|
|
|
// Pressed/Hovered are missing - color for both would be pal.fillColor.text.secondary
|
|
|
|
for ( const auto state : { A::NoState, Q::Disabled } )
|
|
{
|
|
const auto color = ( state == A::NoState )
|
|
? pal.fillColor.controlStrong.defaultColor
|
|
: pal.fillColor.controlStrong.disabled;
|
|
|
|
const auto bullet = Q::Bullet | state | section;
|
|
|
|
setGradient( bullet, color );
|
|
setGradient( bullet | Q::Selected, color );
|
|
}
|
|
}
|
|
|
|
void Editor::setupPopup( const QskFluent2Theme& theme )
|
|
{
|
|
using Q = QskPopup;
|
|
using A = QskAspect;
|
|
|
|
const auto& pal = theme.palette;
|
|
|
|
setHint( Q::Overlay | A::Style, true );
|
|
setGradient( Q::Overlay, pal.background.overlay.defaultColor );
|
|
}
|
|
|
|
void Editor::setupProgressBarMetrics()
|
|
{
|
|
using Q = QskProgressBar;
|
|
using A = QskAspect;
|
|
|
|
setMetric( Q::Groove | A::Size, 1_px );
|
|
setBoxShape( Q::Groove, 100, Qt::RelativeSize );
|
|
|
|
setMetric( Q::Fill | A::Size, 3_px );
|
|
setBoxShape( Q::Fill, 100, Qt::RelativeSize );
|
|
}
|
|
|
|
void Editor::setupProgressBarColors(
|
|
QskAspect::Section section, const QskFluent2Theme& theme )
|
|
{
|
|
using Q = QskProgressBar;
|
|
|
|
const auto& pal = theme.palette;
|
|
|
|
setGradient( Q::Groove | section, pal.strokeColor.controlStrong.defaultColor );
|
|
setGradient( Q::Fill | section, pal.fillColor.accent.defaultColor );
|
|
}
|
|
|
|
void Editor::setupProgressRingMetrics()
|
|
{
|
|
using Q = QskProgressRing;
|
|
using A = QskAspect;
|
|
|
|
static constexpr QskAspect::Variation SmallSize = A::Small;
|
|
static constexpr QskAspect::Variation NormalSize = A::NoVariation;
|
|
static constexpr QskAspect::Variation LargeSize = A::Large;
|
|
|
|
setStrutSize( Q::Fill | SmallSize, { 16_px, 16_px } );
|
|
setStrutSize( Q::Fill | NormalSize, { 32_px, 32_px } );
|
|
setStrutSize( Q::Fill | LargeSize, { 64_px, 64_px } );
|
|
|
|
const auto startAngle = 90, spanAngle = -360;
|
|
setArcMetrics( Q::Fill | SmallSize, startAngle, spanAngle, 1.5 );
|
|
setArcMetrics( Q::Fill | NormalSize, startAngle, spanAngle, 3 );
|
|
setArcMetrics( Q::Fill | LargeSize, startAngle, spanAngle, 6 );
|
|
}
|
|
|
|
void Editor::setupProgressRingColors(
|
|
QskAspect::Section section, const QskFluent2Theme& theme )
|
|
{
|
|
using Q = QskProgressRing;
|
|
|
|
const auto& pal = theme.palette;
|
|
|
|
setGradient( Q::Fill | section, pal.fillColor.accent.defaultColor );
|
|
}
|
|
|
|
void Editor::setupPushButtonMetrics()
|
|
{
|
|
using Q = QskPushButton;
|
|
using A = QskAspect;
|
|
using W = QskFluent2Skin;
|
|
|
|
const qreal h = 32_px;
|
|
setStrutSize( Q::Panel, { 120_px, h } );
|
|
|
|
// 60: not covered by any spec, but 120 is too big for a menu bar
|
|
setStrutSize( Q::Panel | A::Header, { 60_px, h } );
|
|
setStrutSize( Q::Panel | A::Footer, { 60_px, h } );
|
|
|
|
setBoxShape( Q::Panel, 4_px );
|
|
setBoxBorderMetrics( Q::Panel, 1_px );
|
|
setBoxBorderMetrics( Q::Panel | W::Accent | Q::Disabled, 0 );
|
|
|
|
// Fluent buttons don't really have icons,
|
|
|
|
setStrutSize( Q::Icon, 12_px, 12_px );
|
|
setPadding( Q::Icon, { 0, 0, 8_px, 0 } );
|
|
|
|
setFontRole( Q::Text, Fluent2::Body );
|
|
}
|
|
|
|
void Editor::setupPushButtonColors(
|
|
QskAspect::Section section, const QskFluent2Theme& theme )
|
|
{
|
|
using Q = QskPushButton;
|
|
using W = QskFluent2Skin;
|
|
|
|
const auto& pal = theme.palette;
|
|
|
|
for ( const auto variation : { QskAspect::NoVariation, W::Accent } )
|
|
{
|
|
const auto panel = Q::Panel | section | variation;
|
|
const auto text = Q::Text | section | variation;
|
|
const auto icon = Q::Icon | section | variation;
|
|
|
|
for ( const auto state : { QskAspect::NoState, Q::Hovered, Q::Pressed, Q::Checked, Q::Disabled } )
|
|
{
|
|
QRgb panelColor, borderColor1, borderColor2, textColor;
|
|
int graphicRole;
|
|
|
|
if ( variation == W::Accent )
|
|
{
|
|
if ( state == Q::Hovered )
|
|
{
|
|
panelColor = pal.fillColor.accent.secondary;
|
|
borderColor1 = pal.elevation.accentControl.border[0];
|
|
borderColor2 = pal.elevation.accentControl.border[1];
|
|
textColor = pal.fillColor.textOnAccent.primary;
|
|
graphicRole = W::GraphicRoleFillColorTextOnAccentPrimary;
|
|
}
|
|
else if ( state == Q::Pressed || state == Q::Checked )
|
|
{
|
|
panelColor = pal.fillColor.accent.tertiary;
|
|
borderColor1 = borderColor2 = pal.strokeColor.control.onAccentDefault;
|
|
textColor = pal.fillColor.textOnAccent.secondary;
|
|
graphicRole = W::GraphicRoleFillColorTextOnAccentSecondary;
|
|
}
|
|
else if ( state == Q::Disabled )
|
|
{
|
|
panelColor = pal.fillColor.accent.disabled;
|
|
borderColor1 = borderColor2 = panelColor; // irrelevant: width is 0
|
|
textColor = pal.fillColor.textOnAccent.disabled;
|
|
graphicRole = W::GraphicRoleFillColorTextOnAccentDisabled;
|
|
}
|
|
else
|
|
{
|
|
panelColor = pal.fillColor.accent.defaultColor;
|
|
borderColor1 = pal.elevation.accentControl.border[0];
|
|
borderColor2 = pal.elevation.accentControl.border[1];
|
|
textColor = pal.fillColor.textOnAccent.primary;
|
|
graphicRole = W::GraphicRoleFillColorTextOnAccentPrimary;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( state == Q::Hovered )
|
|
{
|
|
panelColor = pal.fillColor.control.secondary;
|
|
borderColor1 = pal.elevation.control.border[0];
|
|
borderColor2 = pal.elevation.control.border[1];
|
|
textColor = pal.fillColor.text.primary;
|
|
graphicRole = W::GraphicRoleFillColorTextPrimary;
|
|
}
|
|
else if ( state == Q::Pressed || state == Q::Checked )
|
|
{
|
|
panelColor = pal.fillColor.control.tertiary;
|
|
borderColor1 = borderColor2 = pal.strokeColor.control.defaultColor;
|
|
textColor = pal.fillColor.text.secondary;
|
|
graphicRole = W::GraphicRoleFillColorTextSecondary;
|
|
}
|
|
else if ( state == Q::Disabled )
|
|
{
|
|
panelColor = pal.fillColor.control.disabled;
|
|
borderColor1 = borderColor2 = pal.strokeColor.control.defaultColor;
|
|
textColor = pal.fillColor.text.disabled;
|
|
graphicRole = W::GraphicRoleFillColorTextDisabled;
|
|
}
|
|
else
|
|
{
|
|
panelColor = pal.fillColor.control.defaultColor;
|
|
borderColor1 = pal.elevation.control.border[0];
|
|
borderColor2 = pal.elevation.control.border[0];
|
|
textColor = pal.fillColor.text.primary;
|
|
graphicRole = W::GraphicRoleFillColorTextPrimary;
|
|
}
|
|
}
|
|
|
|
panelColor = rgbSolid( panelColor, pal.background.solid.base );
|
|
|
|
setGradient( panel | state, panelColor );
|
|
|
|
setBoxBorderGradient( panel | state,
|
|
borderColor1, borderColor2, panelColor );
|
|
|
|
setColor( text | state, textColor );
|
|
setGraphicRole( icon | state, graphicRole );
|
|
}
|
|
}
|
|
}
|
|
|
|
void Editor::setupRadioBoxMetrics()
|
|
{
|
|
using Q = QskRadioBox;
|
|
|
|
setSpacing( Q::Button, 8_px );
|
|
setStrutSize( Q::Button, { 115_px, 38_px } );
|
|
|
|
/*
|
|
We do not have an indicator - states are indicated by the panel border
|
|
|
|
However the colors of the inner side of the border are not solid for
|
|
the selected states and we use a dummy indicator to get this done.
|
|
|
|
How to solve this in a better way, TODO ...
|
|
*/
|
|
|
|
setBoxShape( Q::CheckIndicator, 100, Qt::RelativeSize );
|
|
setBoxBorderMetrics( Q::CheckIndicator, 0 );
|
|
setBoxBorderMetrics( Q::CheckIndicator | Q::Selected, 1_px );
|
|
setBoxBorderMetrics( Q::CheckIndicator | Q::Pressed | Q::Selected, 1_px );
|
|
|
|
setBoxShape( Q::CheckIndicatorPanel, 100, Qt::RelativeSize );
|
|
setStrutSize( Q::CheckIndicatorPanel, { 20_px, 20_px } );
|
|
|
|
setBoxBorderMetrics( Q::CheckIndicatorPanel, 1_px );
|
|
|
|
setBoxBorderMetrics( Q::CheckIndicatorPanel | Q::Selected, 0 );
|
|
setPadding( Q::CheckIndicatorPanel | Q::Selected, { 5_px, 5_px } ); // indicator "strut size"
|
|
|
|
setPadding( Q::CheckIndicatorPanel | Q::Hovered | Q::Selected, { 4_px, 4_px } ); // indicator "strut size"
|
|
setPadding( Q::CheckIndicatorPanel | Q::Pressed, { 7_px, 7_px } ); // indicator "strut size"
|
|
|
|
setBoxBorderMetrics( Q::CheckIndicatorPanel | Q::Pressed | Q::Selected, 0 );
|
|
setPadding( Q::CheckIndicatorPanel | Q::Pressed | Q::Selected, { 6_px, 6_px } ); // indicator "strut size"
|
|
|
|
setBoxBorderMetrics( Q::CheckIndicatorPanel | Q::Disabled | Q::Selected, 0 );
|
|
setPadding( Q::CheckIndicatorPanel | Q::Disabled | Q::Selected, { 6_px, 6_px } ); // indicator "strut size"
|
|
|
|
setFontRole( Q::Text, Fluent2::Body );
|
|
}
|
|
|
|
void Editor::setupRadioBoxColors(
|
|
QskAspect::Section section, const QskFluent2Theme& theme )
|
|
{
|
|
using Q = QskRadioBox;
|
|
using A = QskAspect;
|
|
|
|
const auto& pal = theme.palette;
|
|
|
|
for ( const auto state1 : { A::NoState, Q::Hovered, Q::Pressed, Q::Disabled } )
|
|
{
|
|
for ( const auto state2 : { A::NoState, Q::Selected } )
|
|
{
|
|
const auto states = state1 | state2;
|
|
|
|
auto indicatorColor = pal.fillColor.textOnAccent.primary;
|
|
if ( !( states & Q::Selected ) )
|
|
indicatorColor = QskRgb::toTransparent( indicatorColor, 0 );
|
|
|
|
auto textColor = pal.fillColor.text.primary;
|
|
if ( states & Q::Disabled )
|
|
textColor = pal.fillColor.text.disabled;
|
|
|
|
QRgb panelBorderColor;
|
|
if ( states & ( Q::Disabled | Q::Pressed ) )
|
|
panelBorderColor = pal.strokeColor.controlStrong.disabled;
|
|
else
|
|
panelBorderColor = pal.strokeColor.controlStrong.defaultColor;
|
|
|
|
auto panelColor = pal.fillColor.accent.defaultColor;
|
|
|
|
if ( states == A::NoState )
|
|
{
|
|
panelColor = pal.fillColor.controlAlt.secondary;
|
|
}
|
|
else if ( states == Q::Selected )
|
|
{
|
|
}
|
|
else if ( states == Q::Hovered )
|
|
{
|
|
panelColor = pal.fillColor.controlAlt.tertiary;
|
|
}
|
|
else if ( states == ( Q::Hovered | Q::Selected ) )
|
|
{
|
|
panelColor = pal.fillColor.accent.secondary;
|
|
}
|
|
else if ( states == Q::Pressed )
|
|
{
|
|
panelColor = pal.fillColor.controlAlt.quaternary;
|
|
}
|
|
else if ( states == ( Q::Pressed | Q::Selected ) )
|
|
{
|
|
panelColor = pal.fillColor.accent.tertiary;
|
|
}
|
|
else if ( states == Q::Disabled )
|
|
{
|
|
panelColor = pal.fillColor.controlAlt.disabled;
|
|
}
|
|
else if ( states == ( Q::Disabled | Q::Selected ) )
|
|
{
|
|
panelColor = pal.fillColor.accent.disabled;
|
|
}
|
|
|
|
const auto panel = Q::CheckIndicatorPanel | section | states;
|
|
const auto indicator = Q::CheckIndicator | section | states;
|
|
const auto text = Q::Text | section | states;
|
|
|
|
|
|
#if 0
|
|
// we have different colors when making colors solid early. TODO ...
|
|
panelColor = rgbSolid2( panelColor, pal.background.solid.base );
|
|
indicatorColor = rgbSolid2( indicatorColor, pal.background.solid.base );
|
|
#endif
|
|
setBoxBorderGradient( indicator, pal.elevation.circle.border, panelColor );
|
|
|
|
setGradient( panel, panelColor );
|
|
setBoxBorderColors( panel, panelBorderColor );
|
|
|
|
setGradient( indicator, indicatorColor );
|
|
|
|
setColor( text, textColor );
|
|
}
|
|
}
|
|
}
|
|
|
|
void Editor::setupScrollViewMetrics()
|
|
{
|
|
using A = QskAspect;
|
|
using Q = QskScrollView;
|
|
|
|
for ( auto subControl : { Q::HorizontalScrollBar, Q::VerticalScrollBar } )
|
|
{
|
|
setMetric( subControl | A::Size, 6_px );
|
|
|
|
// The scrollbar is expanding, when being hovered/pressed
|
|
|
|
const qreal padding = 4_px;
|
|
|
|
if ( subControl == Q::HorizontalScrollBar )
|
|
setPadding( Q::HorizontalScrollBar, 0, padding, 0, 0 );
|
|
else
|
|
setPadding( Q::VerticalScrollBar, padding, 0, 0, 0 );
|
|
|
|
setPadding( subControl | Q::Hovered, 0 );
|
|
setPadding( subControl | Q::Pressed, 0 );
|
|
|
|
setBoxShape( subControl, 100, Qt::RelativeSize );
|
|
setAnimation( subControl | A::Metric, 100 );
|
|
}
|
|
|
|
/*
|
|
The scroll bars are actually above the viewport, what is not
|
|
supported by the skinlet. Do we want to have this. TODO ...
|
|
*/
|
|
|
|
// handles
|
|
|
|
setBoxShape( Q::HorizontalScrollHandle, 100, Qt::RelativeSize );
|
|
setBoxShape( Q::VerticalScrollHandle, 100, Qt::RelativeSize );
|
|
|
|
const auto handleExtent = 40_px;
|
|
setStrutSize( Q::HorizontalScrollHandle, handleExtent, 0.0 );
|
|
setStrutSize( Q::VerticalScrollHandle, 0.0, handleExtent );
|
|
}
|
|
|
|
void Editor::setupScrollViewColors(
|
|
QskAspect::Section section, const QskFluent2Theme& theme )
|
|
{
|
|
using A = QskAspect;
|
|
using Q = QskScrollView;
|
|
|
|
const auto& pal = theme.palette;
|
|
|
|
{
|
|
const auto fillColor = pal.fillColor.controlStrong.defaultColor;
|
|
|
|
setGradient( Q::HorizontalScrollHandle | section, fillColor );
|
|
setGradient( Q::VerticalScrollHandle | section, fillColor );
|
|
}
|
|
|
|
for ( auto subControl : { Q::HorizontalScrollBar, Q::VerticalScrollBar } )
|
|
{
|
|
auto fillColor = pal.fillColor.acrylic.background;
|
|
|
|
#if 1
|
|
/*
|
|
With Fluent2 the scroll bar is supposed to be on top of scrollable
|
|
item. QskScrollViewSkinlet does not support this yet and we
|
|
always have the scrollbar on top of the panel. For the light
|
|
scheme this leads to white on white, so we better shade the scrollbar
|
|
for the moment: TODO ...
|
|
*/
|
|
const auto v = qBlue( fillColor );
|
|
if ( v > 250 )
|
|
{
|
|
if ( v == qRed( fillColor ) && v == qGreen( fillColor ) )
|
|
fillColor = qRgba( 240, 240, 240, qAlpha( fillColor ) );
|
|
}
|
|
#endif
|
|
|
|
setGradient( subControl, QskRgb::toTransparent( fillColor, 0 ) );
|
|
setGradient( subControl | Q::Hovered, fillColor );
|
|
setGradient( subControl | Q::Pressed, fillColor );
|
|
|
|
setAnimation( subControl | A::Color, 100 );
|
|
}
|
|
}
|
|
|
|
void Editor::setupSegmentedBarMetrics()
|
|
{
|
|
using Q = QskSegmentedBar;
|
|
using A = QskAspect;
|
|
|
|
const QSizeF segmentStrutSize( 120_px, 32_px );
|
|
|
|
setBoxBorderMetrics( Q::Panel, 1_px );
|
|
setBoxBorderMetrics( Q::Panel | Q::Selected | Q::Disabled, 0 );
|
|
setSpacing( Q::Panel, 8_px );
|
|
|
|
setStrutSize( Q::Icon, { 12_px, 12_px } );
|
|
|
|
setFontRole( Q::Text, Fluent2::Body );
|
|
|
|
setStrutSize( Q::Segment | A::Horizontal, segmentStrutSize );
|
|
setStrutSize( Q::Segment | A::Vertical, segmentStrutSize.transposed() );
|
|
setBoxShape( Q::Segment, 4_px );
|
|
setPadding( Q::Segment, { 8_px, 0, 8_px, 0 } );
|
|
}
|
|
|
|
void Editor::setupSegmentedBarColors(
|
|
QskAspect::Section section, const QskFluent2Theme& theme )
|
|
{
|
|
using Q = QskSegmentedBar;
|
|
using A = QskAspect;
|
|
using W = QskFluent2Skin;
|
|
|
|
const auto& pal = theme.palette;
|
|
|
|
auto panelColor = pal.fillColor.control.defaultColor;
|
|
panelColor = rgbSolid( panelColor, pal.background.solid.base );
|
|
|
|
setGradient( Q::Panel, panelColor );
|
|
|
|
for ( const auto state1 : { A::NoState, Q::Hovered, Q::Disabled } )
|
|
{
|
|
for ( const auto state2 : { A::NoState, Q::Selected } )
|
|
{
|
|
const auto states = state1 | state2;
|
|
|
|
QRgb segmentColor, borderColor1, borderColor2, textColor;
|
|
int graphicRole;
|
|
|
|
if ( states == A::NoState )
|
|
{
|
|
segmentColor = pal.fillColor.control.defaultColor;
|
|
borderColor1 = pal.elevation.control.border[0];
|
|
borderColor2 = pal.elevation.control.border[1];
|
|
textColor = pal.fillColor.text.primary;
|
|
|
|
graphicRole = W::GraphicRoleFillColorTextPrimary;
|
|
}
|
|
else if ( states == Q::Hovered )
|
|
{
|
|
segmentColor = pal.fillColor.control.secondary;
|
|
borderColor1 = pal.elevation.control.border[0];
|
|
borderColor2 = pal.elevation.control.border[1];
|
|
textColor = pal.fillColor.text.primary;
|
|
|
|
graphicRole = W::GraphicRoleFillColorTextPrimary;
|
|
}
|
|
else if ( states == ( Q::Selected | Q::Disabled ) )
|
|
{
|
|
segmentColor = pal.fillColor.accent.disabled;
|
|
borderColor1 = borderColor2 = pal.strokeColor.control.defaultColor;
|
|
textColor = pal.fillColor.textOnAccent.disabled;
|
|
|
|
graphicRole = W::GraphicRoleFillColorTextOnAccentDisabled;
|
|
}
|
|
else if ( states & Q::Selected )
|
|
{
|
|
segmentColor = pal.fillColor.accent.defaultColor;
|
|
borderColor1 = pal.elevation.control.border[0];
|
|
borderColor2 = pal.elevation.control.border[1];
|
|
textColor = pal.fillColor.textOnAccent.primary;
|
|
|
|
graphicRole = W::GraphicRoleFillColorTextOnAccentPrimary;
|
|
}
|
|
else if ( states & Q::Disabled )
|
|
{
|
|
segmentColor = pal.fillColor.control.disabled;
|
|
borderColor1 = borderColor2 = pal.strokeColor.control.defaultColor;
|
|
textColor = pal.fillColor.text.disabled;
|
|
graphicRole = W::GraphicRoleFillColorTextDisabled;
|
|
}
|
|
|
|
const auto segment = Q::Segment | section | states;
|
|
const auto text = Q::Text | section | states;
|
|
const auto icon = Q::Icon | section | states;
|
|
|
|
segmentColor = rgbSolid( segmentColor, pal.background.solid.base );
|
|
|
|
setGradient( segment, segmentColor );
|
|
setBoxBorderGradient( segment, borderColor1, borderColor2, panelColor );
|
|
|
|
setColor( text, textColor );
|
|
|
|
setGraphicRole( icon, graphicRole );
|
|
}
|
|
}
|
|
}
|
|
|
|
void Editor::setupSeparatorMetrics()
|
|
{
|
|
using Q = QskSeparator;
|
|
using A = QskAspect;
|
|
|
|
setMetric( Q::Panel | A::Size, 1_px );
|
|
setBoxShape( Q::Panel, 0 );
|
|
setBoxBorderMetrics( Q::Panel, 0 );
|
|
}
|
|
|
|
void Editor::setupSeparatorColors(
|
|
QskAspect::Section section, const QskFluent2Theme& theme )
|
|
{
|
|
using Q = QskSeparator;
|
|
|
|
const auto& pal = theme.palette;
|
|
setGradient( Q::Panel | section, pal.strokeColor.divider.defaultColor );
|
|
}
|
|
|
|
void Editor::setupSliderMetrics()
|
|
{
|
|
using Q = QskSlider;
|
|
using A = QskAspect;
|
|
|
|
const qreal extent = 22_px;
|
|
|
|
setMetric( Q::Panel | A::Size, extent );
|
|
setBoxShape( Q::Panel, 0 );
|
|
setBoxBorderMetrics( Q::Panel, 0 );
|
|
|
|
setPadding( Q::Panel | A::Horizontal, QskMargins( 0.5 * extent, 0 ) );
|
|
setPadding( Q::Panel | A::Vertical, QskMargins( 0, 0.5 * extent ) );
|
|
|
|
for ( auto subControl : { Q::Groove, Q::Fill } )
|
|
{
|
|
setMetric( subControl | A::Size, 4_px );
|
|
setBoxShape( subControl, 100, Qt::RelativeSize );
|
|
}
|
|
|
|
const auto shadowSpread = 1_px;
|
|
|
|
setStrutSize( Q::Handle, { extent - shadowSpread, extent - shadowSpread } );
|
|
setBoxShape( Q::Handle, 100, Qt::RelativeSize );
|
|
|
|
setShadowMetrics( Q::Handle, { shadowSpread, 0.0 } );
|
|
|
|
setBoxBorderMetrics( Q::Handle, 5_px );
|
|
setBoxBorderMetrics( Q::Handle | Q::Hovered, 4_px );
|
|
setBoxBorderMetrics( Q::Handle | Q::Pressed, 6_px );
|
|
setBoxBorderMetrics( Q::Handle | Q::Disabled, 6_px );
|
|
|
|
setFlag( Q::Tick | A::Option, Qsk::Maybe );
|
|
setStrutSize( Q::Tick | A::Horizontal, 1_px, -1 );
|
|
setStrutSize( Q::Tick | A::Vertical, -1, 1_px );
|
|
|
|
setAnimation( Q::Handle | A::Metric | A::Position, 100 );
|
|
}
|
|
|
|
void Editor::setupSliderColors(
|
|
QskAspect::Section section, const QskFluent2Theme& theme )
|
|
{
|
|
using Q = QskSlider;
|
|
using A = QskAspect;
|
|
|
|
const auto& pal = theme.palette;
|
|
|
|
const auto borderColor = pal.fillColor.controlSolid.defaultColor;
|
|
setBoxBorderColors( Q::Handle, borderColor );
|
|
|
|
{
|
|
const auto gradient = pal.elevation.circle.border;
|
|
|
|
#if 1
|
|
/*
|
|
we can't set gradients as shadows - using the color, that
|
|
lies in the center of the gradient instead. TODO ...
|
|
*/
|
|
auto shadowColor = QskRgb::interpolated( gradient[0], gradient[1], 0.5 );
|
|
shadowColor = rgbFlattened( shadowColor, borderColor );
|
|
#endif
|
|
|
|
setShadowColor( Q::Handle, rgbFlattened( shadowColor, borderColor ) );
|
|
}
|
|
|
|
for ( auto state : { A::NoState, Q::Hovered, Q::Pressed, Q::Disabled } )
|
|
{
|
|
QRgb grooveColor, fillColor, handleColor;
|
|
|
|
if ( state == A::NoState || state == Q::Hovered )
|
|
{
|
|
grooveColor = pal.fillColor.controlStrong.defaultColor;
|
|
fillColor = pal.fillColor.accent.defaultColor;
|
|
handleColor = pal.fillColor.accent.defaultColor;
|
|
}
|
|
else if ( state == Q::Pressed )
|
|
{
|
|
grooveColor = pal.fillColor.controlStrong.defaultColor;
|
|
handleColor = pal.fillColor.accent.tertiary;
|
|
fillColor = pal.fillColor.accent.defaultColor;
|
|
}
|
|
else if ( state == Q::Disabled )
|
|
{
|
|
grooveColor = pal.fillColor.controlStrong.disabled;
|
|
fillColor = pal.fillColor.accent.disabled;
|
|
handleColor = grooveColor;
|
|
}
|
|
|
|
grooveColor = rgbSolid( grooveColor, pal.background.solid.base );
|
|
|
|
setGradient( Q::Groove | section | state, grooveColor );
|
|
setGradient( Q::Fill | section | state, fillColor );
|
|
setGradient( Q::Handle | section | state, handleColor );
|
|
}
|
|
|
|
setGradient( Q::Tick, pal.fillColor.controlSolid.defaultColor );
|
|
}
|
|
|
|
void Editor::setupSpinBoxMetrics()
|
|
{
|
|
using Q = QskSpinBox;
|
|
|
|
/*
|
|
The F2 NumberBox has 2 modes for the Up/Down panels ( a.k.a Spinner ):
|
|
|
|
- compact ( -> QskSpinBox::UpDownControl )
|
|
- inline ( -> QskSpinBox::ButtonsRight )
|
|
|
|
TODO: in compact mode the panels/indicators are blown up, when being hovered
|
|
*/
|
|
setHint( Q::Panel | QskAspect::Style, Q::ButtonsRight );
|
|
|
|
setStrutSize( Q::Panel, { -1, 32_px } );
|
|
setBoxBorderMetrics( Q::Panel, 1_px );
|
|
setBoxShape( Q::Panel, 3_px );
|
|
|
|
setAlignment( Q::Text, Qt::AlignLeft | Qt::AlignVCenter );
|
|
setFontRole( Q::Text, Fluent2::Body );
|
|
|
|
setPadding( Q::TextPanel, { 11_px, 0, 11_px, 0 } );
|
|
|
|
for ( auto panel : { Q::UpPanel, Q::DownPanel } )
|
|
setStrutSize( panel, 32_px, 18_px );
|
|
|
|
setSymbol( Q::UpIndicator, symbol( "chevron_up" ) );
|
|
setSymbol( Q::DownIndicator, symbol( "chevron_down" ) );
|
|
|
|
setPadding( Q::UpPanel, { 0, 1_px, 0, 0 } );
|
|
setPadding( Q::DownPanel, { 0, 0, 0, 1_px } );
|
|
|
|
#if 0
|
|
// QskSpinBox::Pressed is missing yet
|
|
setBoxBorderMetrics( Q::Panel | Q::Pressed, { 1_px, 1_px, 1_px, 2_px } );
|
|
#endif
|
|
}
|
|
|
|
void Editor::setupSpinBoxColors(
|
|
QskAspect::Section section, const QskFluent2Theme& theme )
|
|
{
|
|
using Q = QskSpinBox;
|
|
using A = QskAspect;
|
|
|
|
const auto& pal = theme.palette;
|
|
|
|
for ( auto state : { A::NoState, Q::Hovered, Q::Focused, Q::Disabled } )
|
|
{
|
|
QRgb panelColor, borderColor1, borderColor2;
|
|
|
|
if ( state == A::NoState )
|
|
{
|
|
panelColor = pal.fillColor.control.defaultColor;
|
|
borderColor1 = pal.elevation.control.border[0];
|
|
borderColor2 = pal.elevation.control.border[1];
|
|
}
|
|
else if ( state == Q::Hovered )
|
|
{
|
|
panelColor = pal.fillColor.control.secondary;
|
|
borderColor1 = pal.elevation.textControl.border[0];
|
|
borderColor2 = pal.elevation.textControl.border[1];
|
|
}
|
|
else if ( state == Q::Focused )
|
|
{
|
|
// Focused (Pressed doesn't exist yet):
|
|
|
|
panelColor = pal.fillColor.control.inputActive;
|
|
borderColor1 = pal.elevation.textControl.border[0];
|
|
borderColor2 = pal.fillColor.accent.defaultColor;
|
|
}
|
|
else if ( state == Q::Disabled )
|
|
{
|
|
panelColor = pal.fillColor.control.disabled;
|
|
borderColor1 = borderColor2 = pal.strokeColor.control.defaultColor;
|
|
}
|
|
|
|
QRgb textColor;
|
|
int graphicRole;
|
|
|
|
if ( state != Q::Disabled )
|
|
{
|
|
textColor = pal.fillColor.text.primary;
|
|
graphicRole = QskFluent2Skin::GraphicRoleFillColorTextSecondary;
|
|
}
|
|
else
|
|
{
|
|
textColor = pal.fillColor.text.disabled;
|
|
graphicRole = QskFluent2Skin::GraphicRoleFillColorTextDisabled;
|
|
}
|
|
|
|
const auto panel = Q::Panel | section | state;
|
|
const auto text = Q::Text | section | state;
|
|
const auto upIndicator = Q::UpIndicator | section | state;
|
|
const auto downIndicator = Q::DownIndicator | section | state;
|
|
|
|
panelColor = rgbSolid( panelColor, pal.background.solid.base );
|
|
|
|
setGradient( panel, panelColor );
|
|
|
|
setBoxBorderGradient( panel, borderColor1, borderColor2, panelColor );
|
|
|
|
if ( state == Q::Focused )
|
|
{
|
|
const auto colors = boxBorderColors( panel );
|
|
|
|
setBoxBorderColors( panel | Q::Decreasing, colors );
|
|
setBoxBorderColors( panel | Q::Increasing, colors );
|
|
}
|
|
|
|
setColor( text, textColor );
|
|
|
|
setGraphicRole( upIndicator, graphicRole );
|
|
setGraphicRole( downIndicator, graphicRole );
|
|
}
|
|
}
|
|
|
|
void Editor::setupTabBarMetrics()
|
|
{
|
|
}
|
|
|
|
void Editor::setupTabBarColors( QskAspect::Section section, const QskFluent2Theme& theme )
|
|
{
|
|
setGradient( QskTabBar::Panel | section, theme.palette.background.solid.base );
|
|
}
|
|
|
|
void Editor::setupTabButtonMetrics()
|
|
{
|
|
using Q = QskTabButton;
|
|
|
|
setStrutSize( Q::Panel, { -1, 31_px } );
|
|
setPadding( Q::Panel, { 7_px, 0, 7_px, 0 } );
|
|
setBoxShape( Q::Panel, { 7_px, 7_px, 0, 0 } );
|
|
|
|
setAlignment( Q::Text, Qt::AlignLeft | Qt::AlignVCenter );
|
|
|
|
setBoxBorderMetrics( Q::Panel, { 0, 0, 0, 1_px } );
|
|
setBoxBorderMetrics( Q::Panel | Q::Checked, { 1_px, 1_px, 1_px, 0 } );
|
|
|
|
setFontRole( Q::Text, Fluent2::Body );
|
|
setFontRole( Q::Text | Q::Checked, Fluent2::BodyStrong );
|
|
}
|
|
|
|
void Editor::setupTabButtonColors(
|
|
QskAspect::Section section, const QskFluent2Theme& theme )
|
|
{
|
|
using Q = QskTabButton;
|
|
const auto& pal = theme.palette;
|
|
|
|
for ( const auto state : { QskAspect::NoState,
|
|
Q::Checked, Q::Hovered, Q::Pressed, Q::Disabled } )
|
|
{
|
|
QRgb panelColor, textColor;
|
|
|
|
if ( state == Q::Checked )
|
|
{
|
|
panelColor = pal.background.solid.secondary;
|
|
textColor = pal.fillColor.text.primary;
|
|
}
|
|
else if ( state == Q::Hovered )
|
|
{
|
|
panelColor = pal.fillColor.subtle.secondary;
|
|
textColor = pal.fillColor.text.secondary;
|
|
}
|
|
else if ( state == Q::Pressed )
|
|
{
|
|
panelColor = pal.fillColor.subtle.tertiary;
|
|
textColor = pal.fillColor.text.secondary;
|
|
}
|
|
else if ( state == Q::Disabled )
|
|
{
|
|
panelColor = pal.fillColor.control.disabled;
|
|
textColor = pal.fillColor.text.disabled;
|
|
}
|
|
else
|
|
{
|
|
panelColor = pal.fillColor.subtle.tertiary;
|
|
textColor = pal.fillColor.text.secondary;
|
|
}
|
|
|
|
const auto panel = Q::Panel | section | state;
|
|
const auto text = Q::Text | section | state;
|
|
|
|
panelColor = rgbSolid( panelColor, pal.background.solid.base );
|
|
setGradient( panel, panelColor );
|
|
|
|
const auto borderColor = rgbSolid(
|
|
pal.strokeColor.card.defaultColor, pal.background.solid.base );
|
|
|
|
setBoxBorderColors( panel, borderColor );
|
|
|
|
setColor( text, textColor );
|
|
}
|
|
}
|
|
|
|
void Editor::setupTabViewMetrics()
|
|
{
|
|
}
|
|
|
|
void Editor::setupTabViewColors(
|
|
QskAspect::Section section, const QskFluent2Theme& theme )
|
|
{
|
|
using Q = QskTabView;
|
|
setGradient( Q::Page | section, theme.palette.background.solid.secondary );
|
|
}
|
|
|
|
void Editor::setupGraphicLabelMetrics()
|
|
{
|
|
using Q = QskGraphicLabel;
|
|
|
|
setPadding( Q::Panel, 10_px );
|
|
setBoxShape( Q::Panel, 3_px );
|
|
setBoxBorderMetrics( Q::Panel, 1_px );
|
|
}
|
|
|
|
void Editor::setupGraphicLabelColors(
|
|
QskAspect::Section section, const QskFluent2Theme& theme )
|
|
{
|
|
using Q = QskGraphicLabel;
|
|
const auto& pal = theme.palette;
|
|
|
|
#if 1
|
|
setColor( Q::Panel | section, pal.fillColor.subtle.secondary );
|
|
setBoxBorderColors( Q::Panel | section, pal.strokeColor.control.defaultColor );
|
|
#endif
|
|
}
|
|
|
|
void Editor::setupTextLabelMetrics()
|
|
{
|
|
using Q = QskTextLabel;
|
|
|
|
setPadding( Q::Panel, 10_px );
|
|
setBoxShape( Q::Panel, 3_px );
|
|
setBoxBorderMetrics( Q::Panel, 1_px );
|
|
|
|
setFontRole( Q::Text, Fluent2::Body );
|
|
}
|
|
|
|
void Editor::setupTextLabelColors(
|
|
QskAspect::Section section, const QskFluent2Theme& theme )
|
|
{
|
|
using Q = QskTextLabel;
|
|
const auto& pal = theme.palette;
|
|
|
|
#if 1
|
|
setColor( Q::Panel | section, pal.fillColor.subtle.secondary );
|
|
setBoxBorderColors( Q::Panel | section, pal.strokeColor.control.defaultColor );
|
|
#endif
|
|
setColor( Q::Text | section, pal.fillColor.text.primary );
|
|
}
|
|
|
|
void Editor::setupTextFieldMetrics()
|
|
{
|
|
using Q = QskTextField;
|
|
|
|
setStrutSize( Q::Panel, { -1, 30_px } );
|
|
setPadding( Q::Panel, { 11_px, 0, 11_px, 0 } );
|
|
|
|
setBoxBorderMetrics( Q::Panel, 1_px );
|
|
for( const auto& state : { Q::Focused, Q::Editing } )
|
|
setBoxBorderMetrics( Q::Panel | state, { 1_px, 1_px, 1_px, 2_px } );
|
|
|
|
setBoxShape( Q::Panel, 3_px );
|
|
|
|
setAlignment( Q::Text, Qt::AlignLeft | Qt::AlignVCenter );
|
|
setFontRole( Q::Text, Fluent2::Body );
|
|
|
|
setAlignment( Q::PlaceholderText, alignment( Q::Text ) );
|
|
setFontRole( Q::PlaceholderText, fontRole( Q::Text ) );
|
|
}
|
|
|
|
void Editor::setupTextFieldColors(
|
|
QskAspect::Section section, const QskFluent2Theme& theme )
|
|
{
|
|
using Q = QskTextField;
|
|
using SK = QskTextFieldSkinlet;
|
|
using A = QskAspect;
|
|
|
|
const auto& pal = theme.palette;
|
|
|
|
setColor( Q::Panel | SK::Selected, pal.fillColor.accent.selectedTextBackground );
|
|
setColor( Q::Text | SK::Selected, pal.fillColor.textOnAccent.selectedText );
|
|
setColor( Q::PlaceholderText, pal.fillColor.text.secondary );
|
|
|
|
for( const auto state : { A::NoState, Q::Hovered, Q::Focused, Q::Editing, Q::Disabled } )
|
|
{
|
|
QRgb panelColor, borderColor1, borderColor2, textColor;
|
|
|
|
if ( state == A::NoState )
|
|
{
|
|
panelColor = pal.fillColor.control.defaultColor;
|
|
borderColor1 = pal.elevation.textControl.border[0];
|
|
borderColor2 = pal.elevation.textControl.border[1];
|
|
textColor = pal.fillColor.text.primary;
|
|
}
|
|
else if ( state == Q::Hovered )
|
|
{
|
|
panelColor = pal.fillColor.control.secondary;
|
|
borderColor1 = pal.elevation.textControl.border[0];
|
|
borderColor2 = pal.elevation.textControl.border[1];
|
|
textColor = pal.fillColor.text.primary;
|
|
}
|
|
else if ( ( state == Q::Focused ) || ( state == Q::Editing ) )
|
|
{
|
|
panelColor = pal.fillColor.control.inputActive;
|
|
borderColor1 = pal.elevation.textControl.border[0];
|
|
borderColor2 = pal.fillColor.accent.defaultColor;
|
|
textColor = pal.fillColor.text.primary;
|
|
}
|
|
else if ( state == Q::Disabled )
|
|
{
|
|
panelColor = pal.fillColor.control.disabled;
|
|
borderColor1 = borderColor2 = pal.strokeColor.control.defaultColor;
|
|
textColor = pal.fillColor.text.disabled;
|
|
}
|
|
|
|
const auto panel = Q::Panel | section | state;
|
|
const auto text = Q::Text | section | state;
|
|
|
|
panelColor = rgbSolid( panelColor, pal.background.solid.base );
|
|
|
|
setGradient( panel, panelColor );
|
|
setBoxBorderGradient( panel, borderColor1, borderColor2, panelColor );
|
|
|
|
setColor( text, textColor );
|
|
}
|
|
}
|
|
|
|
void Editor::setupSwitchButtonMetrics()
|
|
{
|
|
using Q = QskSwitchButton;
|
|
using A = QskAspect;
|
|
|
|
const QSizeF strutSize( 38_px, 18_px );
|
|
setStrutSize( Q::Groove | A::Horizontal, strutSize );
|
|
setStrutSize( Q::Groove | A::Vertical, strutSize.transposed() );
|
|
setBoxShape( Q::Groove, 100, Qt::RelativeSize );
|
|
|
|
setBoxBorderMetrics( Q::Groove, 1_px );
|
|
setBoxBorderMetrics( Q::Groove | Q::Checked, 0 );
|
|
|
|
setBoxShape( Q::Handle, 100, Qt::RelativeSize );
|
|
setPosition( Q::Handle, 0.1, { QskStateCombination::CombinationNoState, Q::Disabled } );
|
|
setPosition( Q::Handle | Q::Checked, 0.9,
|
|
{ QskStateCombination::CombinationNoState, Q::Disabled } );
|
|
|
|
setBoxBorderMetrics( Q::Handle, 0 );
|
|
setBoxBorderMetrics( Q::Handle | Q::Checked, 1_px );
|
|
setBoxBorderMetrics( Q::Handle | Q::Disabled | Q::Checked, 0 );
|
|
|
|
setStrutSize( Q::Handle, 12_px, 12_px );
|
|
|
|
setStrutSize( Q::Handle | Q::Hovered, 14_px, 14_px,
|
|
{ QskStateCombination::CombinationNoState, Q::Checked } );
|
|
|
|
const QSizeF pressedSize( 17_px, 14_px );
|
|
|
|
setStrutSize( Q::Handle | Q::Pressed | A::Horizontal,
|
|
pressedSize, { QskStateCombination::CombinationNoState, Q::Checked } );
|
|
|
|
setStrutSize( Q::Handle | Q::Pressed | A::Vertical,
|
|
pressedSize.transposed(), { QskStateCombination::CombinationNoState, Q::Checked } );
|
|
|
|
setStrutSize( Q::Handle | Q::Disabled, 12_px, 12_px,
|
|
{ QskStateCombination::CombinationNoState, Q::Checked } );
|
|
|
|
setAnimation( Q::Handle | A::Metric, 100 );
|
|
}
|
|
|
|
void Editor::setupSwitchButtonColors(
|
|
QskAspect::Section section, const QskFluent2Theme& theme )
|
|
{
|
|
using Q = QskSwitchButton;
|
|
using A = QskAspect;
|
|
|
|
const auto& pal = theme.palette;
|
|
|
|
for ( const auto state1 : { A::NoState, Q::Hovered, Q::Pressed, Q::Disabled } )
|
|
{
|
|
for ( const auto state2 : { A::NoState, Q::Checked } )
|
|
{
|
|
const auto states = state1 | state2;
|
|
|
|
QRgb grooveColor, grooveBorderColor, handleColor;
|
|
|
|
if ( states == A::NoState )
|
|
{
|
|
grooveColor = pal.fillColor.controlAlt.secondary;
|
|
grooveBorderColor = pal.strokeColor.controlStrong.defaultColor;
|
|
handleColor = pal.strokeColor.controlStrong.defaultColor;
|
|
}
|
|
else if ( states == Q::Checked )
|
|
{
|
|
grooveColor = pal.fillColor.accent.defaultColor;
|
|
grooveBorderColor = pal.strokeColor.controlStrong.defaultColor;
|
|
handleColor = pal.fillColor.textOnAccent.primary;
|
|
}
|
|
else if ( states == Q::Hovered )
|
|
{
|
|
grooveColor = pal.fillColor.controlAlt.tertiary;
|
|
grooveBorderColor = pal.fillColor.text.secondary;
|
|
handleColor = pal.fillColor.text.secondary;
|
|
}
|
|
else if ( states == ( Q::Hovered | Q::Checked ) )
|
|
{
|
|
grooveColor = pal.fillColor.accent.secondary;
|
|
grooveBorderColor = pal.strokeColor.controlStrong.defaultColor;
|
|
handleColor = pal.fillColor.textOnAccent.primary;
|
|
//handleColor = pal.fillColor.accent.defaultColor;
|
|
}
|
|
else if ( states == Q::Pressed )
|
|
{
|
|
grooveColor = pal.fillColor.controlAlt.quaternary;
|
|
grooveBorderColor = pal.strokeColor.controlStrong.defaultColor;
|
|
handleColor = pal.strokeColor.controlStrong.defaultColor;
|
|
}
|
|
else if ( states == ( Q::Pressed | Q::Checked ) )
|
|
{
|
|
grooveColor = pal.fillColor.accent.tertiary;
|
|
grooveBorderColor = pal.strokeColor.controlStrong.defaultColor;
|
|
handleColor = pal.fillColor.textOnAccent.primary;
|
|
}
|
|
else if ( states == Q::Disabled )
|
|
{
|
|
grooveColor = pal.fillColor.controlAlt.disabled;
|
|
grooveBorderColor = pal.fillColor.text.disabled;
|
|
handleColor = pal.fillColor.text.disabled;
|
|
}
|
|
else if ( states == ( Q::Disabled | Q::Checked ) )
|
|
{
|
|
grooveColor = pal.fillColor.accent.disabled;
|
|
grooveBorderColor = pal.fillColor.accent.disabled;
|
|
handleColor = pal.fillColor.textOnAccent.disabled;
|
|
}
|
|
|
|
const auto groove = Q::Groove | section | states;
|
|
const auto handle = Q::Handle | section | states;
|
|
|
|
grooveColor = rgbSolid( grooveColor, pal.background.solid.base );
|
|
|
|
setGradient( groove, grooveColor );
|
|
setBoxBorderColors( groove, grooveBorderColor );
|
|
|
|
setGradient( handle, handleColor );
|
|
setBoxBorderGradient( handle, pal.elevation.circle.border, grooveColor );
|
|
}
|
|
}
|
|
}
|
|
|
|
void Editor::setupSubWindow( const QskFluent2Theme& theme )
|
|
{
|
|
using Q = QskSubWindow;
|
|
using A = QskAspect;
|
|
|
|
const auto& pal = theme.palette;
|
|
|
|
setBoxShape( Q::Panel, 7_px );
|
|
setBoxBorderMetrics( Q::Panel, 1_px );
|
|
setBoxBorderColors( Q::Panel, pal.strokeColor.surface.defaultColor );
|
|
setGradient( Q::Panel, pal.background.layer.alt );
|
|
setShadowMetrics( Q::Panel, theme.shadow.dialog.metrics );
|
|
setShadowColor( Q::Panel, theme.shadow.dialog.color );
|
|
|
|
setHint( Q::TitleBarPanel | QskAspect::Style, Q::NoDecoration );
|
|
setPadding( Q::TitleBarPanel, { 24_px, 31_px, 24_px, 0 } );
|
|
|
|
setFontRole( Q::TitleBarText, Fluent2::Subtitle );
|
|
setColor( Q::TitleBarText, pal.fillColor.text.primary );
|
|
setAlignment( Q::TitleBarText, Qt::AlignLeft );
|
|
setTextOptions( Q::TitleBarText, Qt::ElideRight, QskTextOptions::NoWrap );
|
|
|
|
setAnimation( Q::Panel | A::Position, 300, QEasingCurve::OutCubic );
|
|
}
|
|
|
|
void Editor::setupDialogSubWindow( const QskFluent2Theme& )
|
|
{
|
|
using Q = QskDialogSubWindow;
|
|
|
|
setFontRole( Q::DialogTitle, Fluent2::Subtitle );
|
|
setAlignment( Q::DialogTitle, Qt::AlignLeft | Qt::AlignVCenter );
|
|
setTextOptions( Q::DialogTitle, Qt::ElideRight, QskTextOptions::WordWrap );
|
|
}
|
|
|
|
void Editor::setupVirtualKeyboardMetrics()
|
|
{
|
|
using Q = QskVirtualKeyboard;
|
|
|
|
setMargin( Q::ButtonPanel, 2_px );
|
|
setFontRole( Q::ButtonText, Fluent2::BodyStrong );
|
|
setPadding( Q::Panel, 8_px );
|
|
}
|
|
|
|
void Editor::setupVirtualKeyboardColors(
|
|
QskAspect::Section, const QskFluent2Theme& theme )
|
|
{
|
|
using Q = QskVirtualKeyboard;
|
|
|
|
const auto& pal = theme.palette;
|
|
|
|
setGradient( Q::ButtonPanel, pal.fillColor.control.defaultColor );
|
|
setGradient( Q::ButtonPanel | Q::Hovered, pal.fillColor.control.secondary );
|
|
setGradient( Q::ButtonPanel | QskPushButton::Pressed, pal.fillColor.control.tertiary );
|
|
|
|
setColor( Q::ButtonText, pal.fillColor.text.primary );
|
|
setColor( Q::ButtonText | QskPushButton::Pressed, pal.fillColor.text.secondary );
|
|
|
|
setGradient( Q::Panel, pal.background.solid.tertiary );
|
|
}
|
|
|
|
QskFluent2Skin::QskFluent2Skin( QObject* parent )
|
|
: Inherited( parent )
|
|
{
|
|
declareSkinlet< QskTextField, QskFluent2TextFieldSkinlet >();
|
|
|
|
setupFonts();
|
|
|
|
Editor editor( &hintTable() );
|
|
editor.setupMetrics();
|
|
}
|
|
|
|
void QskFluent2Skin::addTheme( QskAspect::Section section, const QskFluent2Theme& theme )
|
|
{
|
|
if ( section == QskAspect::Body )
|
|
{
|
|
// design flaw: we can't have section sensitive filters. TODO ..
|
|
setupGraphicFilters( theme );
|
|
}
|
|
|
|
Editor editor( &hintTable() );
|
|
editor.setupColors( section, theme );
|
|
}
|
|
|
|
QskFluent2Skin::~QskFluent2Skin()
|
|
{
|
|
}
|
|
|
|
void QskFluent2Skin::initHints()
|
|
{
|
|
struct
|
|
{
|
|
QskFluent2Theme::BaseColors baseColors;
|
|
QskFluent2Theme::AccentColors accentColors;
|
|
} colors[2];
|
|
|
|
if( colorScheme() != QskSkin::DarkScheme )
|
|
{
|
|
colors[0].baseColors = { rgbGray( 243 ), rgbGray( 249 ), rgbGray( 238 ) };
|
|
colors[0].accentColors = { 0xff0078d4, 0xff005eb7, 0xff003d92, 0xff001968 };
|
|
|
|
colors[1].baseColors = { rgbGray( 249 ), rgbGray( 249 ), rgbGray( 238 ) };
|
|
colors[1].accentColors = colors[0].accentColors;
|
|
}
|
|
else
|
|
{
|
|
colors[0].baseColors = { rgbGray( 32 ), rgbGray( 40 ), rgbGray( 28 ) };
|
|
colors[0].accentColors = { 0xff0078d4, 0xff0093f9, 0xff60ccfe, 0xff98ecfe };
|
|
|
|
colors[1].baseColors = { rgbGray( 40 ), rgbGray( 44 ), rgbGray( 28 ) };
|
|
colors[1].accentColors = colors[0].accentColors;
|
|
}
|
|
|
|
setupFonts();
|
|
|
|
Editor editor( &hintTable() );
|
|
editor.setupMetrics();
|
|
|
|
const QskFluent2Theme themeBody( colorScheme(),
|
|
colors[0].baseColors, colors[0].accentColors );
|
|
|
|
const QskFluent2Theme themeHeader( colorScheme(),
|
|
colors[1].baseColors, colors[1].accentColors );
|
|
|
|
addTheme( QskAspect::Body, themeBody );
|
|
addTheme( QskAspect::Header, themeHeader );
|
|
addTheme( QskAspect::Footer, themeHeader );
|
|
}
|
|
|
|
static inline QFont createFont( qreal size, int lineHeight, QFont::Weight weight )
|
|
{
|
|
Q_UNUSED( lineHeight ); // TODO ...
|
|
|
|
QFont font( QStringLiteral( "Segoe UI" ), -1, weight );
|
|
|
|
static bool checkFont = true;
|
|
if ( checkFont )
|
|
{
|
|
const QFontInfo info( font );
|
|
if ( info.family() != font.family() )
|
|
{
|
|
qWarning() << font.family() <<
|
|
"not found, using" << info.family() << "instead.";
|
|
}
|
|
checkFont = false;
|
|
}
|
|
|
|
// px: 1/96 inch, pt: 1/72 inch
|
|
font.setPointSizeF( size * 72.0 / 96.0 );
|
|
|
|
return font;
|
|
}
|
|
|
|
void QskFluent2Skin::setupFonts()
|
|
{
|
|
// see: https://fluent2.microsoft.design/typography ( Windows )
|
|
|
|
setFont( Fluent2::Caption, createFont( 12_px, 16_px, QFont::Normal ) );
|
|
|
|
setFont( Fluent2::Body, createFont( 14_px, 20_px, QFont::Normal ) );
|
|
setFont( Fluent2::BodyStrong, createFont( 14_px, 20_px, QFont::DemiBold ) );
|
|
setFont( Fluent2::BodyStronger, createFont( 18_px, 24_px, QFont::Normal ) );
|
|
|
|
setFont( Fluent2::Subtitle, createFont( 20_px, 28_px, QFont::DemiBold ) );
|
|
|
|
setFont( Fluent2::Title, createFont( 28_px, 36_px, QFont::Normal ) );
|
|
setFont( Fluent2::LargeTitle, createFont( 40_px, 52_px, QFont::DemiBold ) );
|
|
|
|
setFont( Fluent2::Display, createFont( 68_px, 92_px, QFont::DemiBold ) );
|
|
|
|
// to have something for the unused roles
|
|
QskSkin::completeFontTable();
|
|
}
|
|
|
|
void QskFluent2Skin::setGraphicColor( GraphicRole role, QRgb rgb )
|
|
{
|
|
QskColorFilter colorFilter;
|
|
colorFilter.setMask( QskRgb::RGBAMask );
|
|
colorFilter.addColorSubstitution( QskRgb::Black, rgb );
|
|
|
|
setGraphicFilter( role, colorFilter );
|
|
}
|
|
|
|
void QskFluent2Skin::setupGraphicFilters( const QskFluent2Theme& theme )
|
|
{
|
|
const auto& colors = theme.palette.fillColor;
|
|
|
|
setGraphicColor( GraphicRoleFillColorTextDisabled, colors.text.disabled );
|
|
setGraphicColor( GraphicRoleFillColorTextOnAccentDisabled, colors.textOnAccent.disabled );
|
|
setGraphicColor( GraphicRoleFillColorTextOnAccentPrimary, colors.textOnAccent.primary );
|
|
setGraphicColor( GraphicRoleFillColorTextOnAccentSecondary, colors.textOnAccent.secondary );
|
|
setGraphicColor( GraphicRoleFillColorTextPrimary, colors.text.primary );
|
|
setGraphicColor( GraphicRoleFillColorTextSecondary, colors.text.secondary );
|
|
}
|
|
|
|
#include "moc_QskFluent2Skin.cpp"
|