Merge branch 'uwerat:master' into blurredbox

This commit is contained in:
Rick Vogel 2023-02-13 12:27:37 +01:00 committed by GitHub
commit 77c0c46910
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
279 changed files with 12686 additions and 6023 deletions

View File

@ -127,28 +127,28 @@ jobs:
build-linux-qt-current:
name: Linux Qt 6.3 (current) build
name: Linux Qt 6.4 (current) build
runs-on: ubuntu-latest
env:
DISPLAY: ":1"
steps:
- uses: actions/checkout@v2
- name: Cache Qt
id: cache-qt-6-3
id: cache-qt-6-4
uses: actions/cache@v1 # not v2!
with:
path: ../Qt/6.3.0
key: ${{ runner.os }}-QtCache-Qt6-3
path: ../Qt/6.4.1
key: ${{ runner.os }}-QtCache-Qt6-4
- name: Install Qt
uses: jurplel/install-qt-action@v2
with:
version: '6.3.0'
version: '6.4.1'
host: 'linux'
target: 'desktop'
install-deps: 'true'
modules: 'qtwebengine'
cached: ${{ steps.cache-qt-6-3.outputs.cache-hit }}
cached: ${{ steps.cache-qt-6-4.outputs.cache-hit }}
setup-python: 'true'
tools: ''
set-env: 'true'
@ -174,7 +174,7 @@ jobs:
./examples/bin/gallery &
sleep 10
echo taking screenshot
import -pause 1 -window root screenshot-linux-qt6-3.jpg
import -pause 1 -window root screenshot-linux-qt6-4.jpg
echo killing gallery
killall gallery
echo killing Xvfb
@ -182,8 +182,8 @@ jobs:
- name: Upload smoke test artifacts
uses: actions/upload-artifact@v2
with:
name: screenshot-linux-qt6-3.jpg
path: screenshot-linux-qt6-3.jpg
name: screenshot-linux-qt6-4.jpg
path: screenshot-linux-qt6-4.jpg
build-windows-qt5-15:
@ -297,27 +297,27 @@ jobs:
build-windows-qt-current:
name: Windows Qt 6.3 (current) build
name: Windows Qt 6.4 (current) build
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- name: Cache Qt
id: cache-qt-6-3
id: cache-qt-6-4
uses: actions/cache@v1 # not v2!
with:
path: ../Qt/6.3.0
key: ${{ runner.os }}-QtCache-Qt6-3
path: ../Qt/6.4.1
key: ${{ runner.os }}-QtCache-Qt6-4
- name: Install Qt
uses: jurplel/install-qt-action@v2
with:
version: '6.3.0'
version: '6.4.1'
host: 'windows'
target: 'desktop'
arch: 'win64_msvc2019_64'
install-deps: 'true'
modules: 'qtwebengine'
cached: ${{ steps.cache-qt-6-3.outputs.cache-hit }}
cached: ${{ steps.cache-qt-6-4.outputs.cache-hit }}
setup-python: 'true'
tools: ''
set-env: 'true'
@ -346,7 +346,7 @@ jobs:
Start-Sleep -s 10
- uses: OrbitalOwen/desktop-screenshot-action@0.1
with:
file-name: 'screenshot-windows-qt6-3.jpg'
file-name: 'screenshot-windows-qt6-4.jpg'
- name: Cleanup smoke test
run: taskkill /IM gallery.exe /T
@ -443,26 +443,26 @@ jobs:
run: killall gallery
build-mac-qt-current:
name: MacOS Qt 6.3 (current) build
name: MacOS Qt 6.4 (current) build
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- name: Cache Qt
id: cache-qt-6-3
id: cache-qt-6-4
uses: actions/cache@v1 # not v2!
with:
path: ../Qt/6.3.0
key: ${{ runner.os }}-QtCache-Qt6-3
path: ../Qt/6.4.1
key: ${{ runner.os }}-QtCache-Qt6-4
- name: Install Qt
uses: jurplel/install-qt-action@v2
with:
version: '6.3.0'
version: '6.4.1'
host: 'mac'
target: 'desktop'
install-deps: 'true'
modules: 'qtwebengine'
cached: ${{ steps.cache-qt-6-3.outputs.cache-hit }}
cached: ${{ steps.cache-qt-6-4.outputs.cache-hit }}
setup-python: 'true'
tools: ''
set-env: 'true'
@ -483,6 +483,6 @@ jobs:
sleep 10
- uses: OrbitalOwen/desktop-screenshot-action@0.1
with:
file-name: 'screenshot-macos-qt6-3.jpg'
file-name: 'screenshot-macos-qt6-4.jpg'
- name: Cleanup smoke test
run: killall gallery

View File

@ -27,7 +27,7 @@ controls is limited to the needs of the driving projects.
QSkinny is supposed to run on all platforms being supported by Qt/Quick.
But so far only Linux is actively tested.
It might support all versions Qt >= 5.12, but you can rely on:
It might support all versions Qt >= 5.15, but you can rely on:
- Qt 5.15
- current long term supported ( LTS ) version of Qt

View File

@ -56,18 +56,6 @@
\accessors locale(), setLocale(), resetLocale(), localeChanged()
*/
/*!
\property bool QskControl::autoFillBackground
This property holds whether the background is filled automatically
with the background gradient.
\accessors autoFillBackground(), setAutoFillBackground()
\sa background()
\saqt QWidget::autoFillBackground
*/
/*!
\property bool QskControl::autoLayoutChildren
@ -223,11 +211,8 @@
Sets the margins around the contents of the control
The value is stored in the local hint table for the aspect:
QskControl::Control | QskAspect::Metric | QskAspect::Margin
\param margin Margin for all sides
\aspect QskControl::Control | QskAspect::Metric | QskAspect::Margin
\aspect QskControl::Background | QskAspect::Metric | QskAspect::Padding
\sa contentsRect(), margins(), QskSkinnable::setMarginHint()
*/
@ -235,15 +220,14 @@
/*!
\fn QskControl::setMargins( qreal, qreal, qreal, qreal )
The value is stored in the local hint table for the aspect:
QskControl::Control | QskAspect::Metric | QskAspect::Margin
Sets the margins around the contents of the control
\param left Left margin
\param top Top margin
\param right Right margin
\param bottom Bottom margin
\aspect QskControl::Control | QskAspect::Metric | QskAspect::Margin
\aspect QskControl::Background | QskAspect::Metric | QskAspect::Padding
\sa contentsRect(), margins(), QskSkinnable::setMarginHint()
*/
@ -254,7 +238,7 @@
Sets the margins around the contents of the control
\param margins Margins
\aspect QskControl::Control | QskAspect::Metric | QskAspect::Margin
\aspect QskControl::Background | QskAspect::Metric | QskAspect::Padding
\sa contentsRect(), margins()
\saqt QEvent::ContentsRectChange
@ -265,7 +249,7 @@
Reset the margins to the default value provided from the skin
\aspect QskControl::Control | QskAspect::Metric | QskAspect::Margin
\aspect QskControl::Background | QskAspect::Metric | QskAspect::Padding
\sa contentsRect(), setMargins(), margins()
\saqt QEvent::ContentsRectChange
@ -275,7 +259,7 @@
\fn QskControl::margins() const
\return margins around the contents of the control
\aspect QskControl::Control | QskAspect::Metric | QskAspect::Margin
\aspect QskControl::Background | QskAspect::Metric | QskAspect::Padding
\sa contentsRect(), setMargins()
\saqt QEvent::ContentsRectChange
@ -284,11 +268,12 @@
/*!
\fn QskControl::setBackgroundColor
A conveninece method that enables the \ref autoFillBackground property
and sets a solid color as background. Usually used for debugging
layout problems.
A conveninece method for setting a monochrome gradient as background. Often used
for debugging layout problems.
\sa setBackground(), setAutoFillBackground()
\aspect QskControl::Background | QskAspect::Color
\sa setBackground()
\sa QskQuickItem::DebugForceBackground
*/
@ -296,10 +281,9 @@
\fn QskControl::setBackground
Set the gradient that is used to fill the background,
when \ref autoFillBackground is enabled.
\aspect QskControl::Control | QskAspect::Color
\sa resetBackground(), background(), autoFillBackground()
\aspect QskControl::Background | QskAspect::Color
\sa resetBackground(), background(), setBackgroundColor
*/
/*!
@ -307,18 +291,17 @@
Reset the background gradient to the default colors from the skin
\aspect QskControl::Control | QskAspect::Color
\sa setBackground(), background(), autoFillBackground()
\aspect QskControl::Background | QskAspect::Color
\sa setBackground(), setBackgroundColor(), background()
*/
/*!
\fn QskControl::background() const
\return Gradient that is used to fill the background,
when autoFillBackground is enabled.
\return Gradient that is used to fill the background
\aspect QskControl::Control | QskAspect::Color
\sa setBackground(), resetBackground(), autoFillBackground()
\aspect QskControl::Background | QskAspect::Color
\sa setBackground(), setBackgroundColor(), resetBackground()
*/
/*!
@ -329,6 +312,8 @@
contentsRect() is a rectangle being used for laying out scene graph nodes,
while layoutRect() is used for child items.
\aspect QskControl::Background | QskAspect::Metric | QskAspect::Padding
\sa margins(), setMargins(), layoutRect()
*/
@ -440,25 +425,11 @@
\sa QskSkinnable::subControlContentsRect
*/
/*!
\fn QskControl::setAutoFillBackground
Set or clear the \ref autoFillBackground property
\sa autoFillBackground()
*/
/*!
\fn QskControl::autoFillBackground() const
\return Value of the \ref autoFillBackground property
\sa setAutoFillBackground()
*/
/*!
\fn QskControl::setAutoLayoutChildren
Set or clear the autoLayoutChildren property
\sa autoFillBackground()
\sa autoLayoutChildren()
*/
/*!

View File

@ -9,6 +9,20 @@
#include <QskBoxBorderMetrics.h>
#include <QskBoxShapeMetrics.h>
#include <QskHctColor.h>
#include <QskRgbValue.h>
static inline void setStartStop( Box::FillType type, QskGradient& gradient )
{
qreal x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
if ( type != Box::Horizontal )
y2 = 1.0;
if ( type != Box::Vertical )
x2 = 1.0;
gradient.setLinearDirection( x1, y1, x2, y2 );
}
Box::Box( QQuickItem* parentItem )
: QskBox( parentItem )
@ -19,14 +33,14 @@ Box::Box( QQuickItem* parentItem )
setBoxShapeHint( QskBox::Panel, QskBoxShapeMetrics() );
setBoxBorderMetricsHint( QskBox::Panel, QskBoxBorderMetrics() );
setBoxBorderColorsHint( QskBox::Panel, QskBoxBorderColors() );
setGradientHint( QskBox::Panel, QskGradient() );
setPanelGradient( QskGradient() );
}
void Box::setBackground( FillType type, QGradient::Preset preset, bool inverted )
void Box::setWebGradient( FillType type, QGradient::Preset preset, bool inverted )
{
if ( type == Unfilled )
{
setGradient( QskGradient() );
setPanelGradient( QskGradient() );
return;
}
@ -34,54 +48,73 @@ void Box::setBackground( FillType type, QGradient::Preset preset, bool inverted
if ( type == Solid )
{
const auto& stops = gradient.stops();
const auto color = QskRgb::interpolated(
gradient.startColor(), gradient.endColor(), 0.5 );
const auto color = QskGradientStop::interpolated(
stops.first(), stops.last(), 0.5 );
setGradient( QskGradient( color ) );
gradient.setStops( color );
}
else
{
const auto orientation =
static_cast< QskGradient::Orientation >( type - 2 );
gradient.setOrientation( orientation );
setStartStop( type, gradient );
if ( inverted )
gradient.reverse();
if ( inverted )
gradient.reverse();
setGradient( gradient );
}
setPanelGradient( gradient );
}
void Box::setBackground( FillType type, const QRgb base, bool inverted )
void Box::setTonalGradient( FillType type, const QRgb base, bool inverted )
{
if ( type == Unfilled )
{
setGradient( QskGradient() );
setPanelGradient( QskGradient() );
return;
}
const QskHctColor htcColor( base );
QskGradient gradient;
const QskHctColor htcColor( base );
if ( type == Solid )
{
setGradient( htcColor.toned( 50 ).rgb() );
gradient.setStops( htcColor.toned( 50 ).rgb() );
}
else
else if ( type != Unfilled )
{
const auto dark = htcColor.toned( 40 ).rgb();
const auto light = htcColor.toned( 70 ).rgb();
const auto orientation =
static_cast< QskGradient::Orientation >( type - 2 );
if ( inverted )
setGradient( orientation, dark, light );
else
setGradient( orientation, light, dark );
gradient.setStops( htcColor.toned( 70 ).rgb(),
htcColor.toned( 40 ).rgb() );
}
setStartStop( type, gradient );
if ( inverted )
gradient.reverse();
setPanelGradient( gradient );
}
void Box::setTonalPalette( FillType type, const QRgb base )
{
if ( type == Unfilled || type == Solid )
{
setTonalGradient( type, base );
return;
}
QskGradient gradient;
setStartStop( type, gradient );
{
const QskHctColor hctColor( base );
QVector< QRgb > colors;
colors.reserve( 10 );
for ( int i = 0; i < 10; i++ )
colors += hctColor.toned( 90 - i * 7 ).rgb();
gradient.setStops( qskBuildGradientStops( colors, true ) );
}
setPanelGradient( gradient );
}
void Box::setBorder( BorderType type, const QRgb base )
@ -166,26 +199,30 @@ void Box::setBorderWidth( int width )
void Box::setGradient( QRgb rgb )
{
setGradient( QskGradient( QColor::fromRgba( rgb ) ) );
setGradient( QColor::fromRgba( rgb ) );
}
void Box::setGradient( Qt::GlobalColor color )
{
setGradient( QskGradient( color ) );
setGradient( QColor( color ) );
}
void Box::setGradient( const QColor& color )
{
setGradient( QskGradient( color ) );
setPanelGradient( QskGradient( color ) );
}
void Box::setGradient( QskGradient::Orientation orientation,
void Box::setGradient( FillType fillType,
const QColor& color1, const QColor& color2 )
{
setGradient( QskGradient( orientation, color1, color2 ) );
QskGradientStops stops;
stops += QskGradientStop( 0.0, color1 );
stops += QskGradientStop( 1.0, color2 );
setGradient( fillType, stops );
}
void Box::setGradient( QskGradient::Orientation orientation,
void Box::setGradient( FillType fillType,
const QColor& color1, const QColor& color2, const QColor& color3 )
{
QskGradientStops stops;
@ -193,24 +230,31 @@ void Box::setGradient( QskGradient::Orientation orientation,
stops += QskGradientStop( 0.5, color2 );
stops += QskGradientStop( 1.0, color3 );
setGradient( QskGradient( orientation, stops ) );
setGradient( fillType, stops );
}
void Box::setGradient( const QskGradient& gradient )
void Box::setGradient( FillType fillType, const QskGradientStops& stops )
{
QskGradient gradient;
if ( fillType == Solid )
{
const auto color = QskRgb::interpolated(
stops.first().rgb(), stops.last().rgb(), 0.5 );
gradient.setStops( color );
}
else if ( fillType != Unfilled )
{
gradient.setStops( stops );
}
setStartStop( fillType, gradient );
setPanelGradient( gradient );
}
void Box::setPanelGradient( const QskGradient& gradient )
{
setGradientHint( QskBox::Panel, gradient );
}
void Box::setGradient(
const QskGradient::Orientation orientation, const QRgb base )
{
const QskHctColor hctColor( base );
QVector< QRgb > rgb;
rgb.reserve( 10 );
for ( int i = 0; i < 10; i++ )
rgb += hctColor.toned( 90 - i * 7 ).rgb();
setGradient( QskGradient( orientation, QskGradient::colorStops( rgb, true ) ) );
}

View File

@ -31,9 +31,6 @@ class Box : public QskBox
Box( QQuickItem* parentItem = nullptr );
void setBackground( FillType, QRgb, bool inverted = false );
void setBackground( FillType, QGradient::Preset, bool inverted = false );
void setBorder( BorderType type, QRgb );
void setShape( const QskBoxShapeMetrics& );
@ -51,11 +48,15 @@ class Box : public QskBox
void setGradient( Qt::GlobalColor );
void setGradient( const QColor& );
void setGradient( QskGradient::Orientation, const QColor&, const QColor& );
void setGradient( FillType, const QColor&, const QColor& );
void setGradient( FillType, const QColor&, const QColor&, const QColor& );
void setGradient( FillType, const QskGradientStops& );
void setGradient( QskGradient::Orientation,
const QColor&, const QColor&, const QColor& );
void setTonalGradient( FillType, QRgb, bool inverted = false );
void setWebGradient( FillType, QGradient::Preset, bool inverted = false );
void setGradient( const QskGradient& );
void setGradient( const QskGradient::Orientation, QRgb );
void setTonalPalette( FillType, QRgb );
private:
void setPanelGradient( const QskGradient& );
};

View File

@ -14,13 +14,14 @@
#include <QskBoxBorderColors.h>
#include <QskBoxBorderMetrics.h>
#include <QskBoxShapeMetrics.h>
#include <QskGradient.h>
#include <QskRgbValue.h>
#include <QskObjectCounter.h>
#include <QGuiApplication>
#define TONAL_GRADIENTS 1
namespace
{
// Some leftover definitions from M(aterial)2. TODO ...
@ -71,11 +72,17 @@ static void addTestRectangle( QskLinearBox* parent )
box->setBorderWidth( 10, 20, 40, 20 );
QskBoxShapeMetrics shape( 50, Qt::RelativeSize );
shape.setScalingMode( QskBoxShapeMetrics::Elliptic );
shape.setRadius( Qt::BottomRightCorner, 30 );
shape.setRadius( Qt::TopRightCorner, 70 );
box->setShape( shape );
box->setGradient( QskGradient::Diagonal, QskRgb::DodgerBlue );
#if TONAL_GRADIENTS
box->setTonalPalette( Box::Diagonal, QskRgb::DodgerBlue );
#else
box->setGradient( Box::Diagonal, QskRgb::DodgerBlue, QskRgb::DarkSlateBlue );
#endif
}
static void addRectangles1( QskLinearBox* parent )
@ -84,7 +91,11 @@ static void addRectangles1( QskLinearBox* parent )
Box::Horizontal, Box::Vertical, Box::Diagonal } )
{
auto* rectangle = new MyRectangle( parent );
rectangle->setBackground( type, QskRgb::Teal );
#if TONAL_GRADIENTS
rectangle->setTonalGradient( type, QskRgb::Teal );
#else
rectangle->setGradient( type, Qt::red, Qt::blue );
#endif
}
}
@ -95,7 +106,11 @@ static void addRectangles2( QskLinearBox* parent )
{
auto* rectangle = new MyRectangle( parent );
rectangle->setBorder( Box::Flat, QskRgb::SaddleBrown );
rectangle->setBackground( type, QGradient::SunnyMorning );
#if TONAL_GRADIENTS
rectangle->setWebGradient( type, QGradient::SunnyMorning );
#else
rectangle->setGradient( type, Qt::red, Qt::blue );
#endif
}
}
@ -113,19 +128,19 @@ static void addRectangles3( QskLinearBox* parent )
box = new MyRectangle( parent );
box->setBorder( Box::Sunken1, borderTheme );
box->setGradient( QskGradient::Diagonal, Grey400, Grey500 );
box->setGradient( Box::Diagonal, Grey400, Grey500 );
box = new MyRectangle( parent );
box->setBorder( Box::Raised2, borderTheme );
box->setGradient( QskGradient::Vertical, Grey400, Grey500 );
box->setGradient( Box::Vertical, Grey400, Grey500 );
box = new MyRectangle( parent );
box->setBorder( Box::Raised2, borderTheme );
box->setBackground( Box::Vertical, QGradient::RiverCity, true );
box->setWebGradient( Box::Vertical, QGradient::RiverCity, true );
box = new MyRectangle( parent );
box->setBorder( Box::Sunken2, borderTheme );
box->setBackground( Box::Vertical, QGradient::RiverCity, false );
box->setWebGradient( Box::Vertical, QGradient::RiverCity, false );
}
static void addRectangles4( QskLinearBox* parent )
@ -134,7 +149,11 @@ static void addRectangles4( QskLinearBox* parent )
Box::Horizontal, Box::Vertical, Box::Diagonal } )
{
auto* box = new MyRoundedRectangle( parent );
box->setBackground( type, QskRgb::OrangeRed );
#if TONAL_GRADIENTS
box->setTonalGradient( type, QskRgb::OrangeRed );
#else
box->setGradient( type, Qt::red, Qt::blue );
#endif
}
}
@ -145,7 +164,11 @@ static void addRectangles5( QskLinearBox* parent )
{
auto* box = new MyRoundedRectangle( parent );
box->setBorder( Box::Flat, QskRgb::RoyalBlue );
box->setBackground( type, QskRgb::DeepPink );
#if TONAL_GRADIENTS
box->setTonalGradient( type, QskRgb::DeepPink );
#else
box->setGradient( type, Qt::red, Qt::blue );
#endif
}
}
@ -163,19 +186,19 @@ static void addRectangles6( QskLinearBox* parent )
box = new MyRoundedRectangle( parent );
box->setBorder( Box::Sunken1, borderTheme );
box->setGradient( QskGradient::Diagonal, Grey400, Grey500 );
box->setGradient( Box::Diagonal, Grey400, Grey500 );
box = new MyRoundedRectangle( parent );
box->setBorder( Box::Raised2, borderTheme );
box->setGradient( QskGradient::Vertical, Grey400, Grey500 );
box->setGradient( Box::Vertical, Grey400, Grey500 );
box = new MyRoundedRectangle( parent );
box->setBorder( Box::Raised2, borderTheme );
box->setGradient( QskGradient::Vertical, Lime300, Lime600 );
box->setGradient( Box::Vertical, Lime300, Lime600 );
box = new MyRoundedRectangle( parent );
box->setBorder( Box::Sunken2, borderTheme );
box->setGradient( QskGradient::Vertical, Lime600, Lime300 );
box->setGradient( Box::Vertical, Lime600, Lime300 );
}
static void addRectangles7( QskLinearBox* parent )
@ -184,7 +207,7 @@ static void addRectangles7( QskLinearBox* parent )
Box::Horizontal, Box::Vertical, Box::Diagonal } )
{
auto* box = new MyEllipse( parent );
box->setBackground( type, QskRgb::SlateGrey );
box->setTonalGradient( type, QskRgb::SlateGrey );
}
}
@ -195,7 +218,7 @@ static void addRectangles8( QskLinearBox* parent )
{
auto* box = new MyEllipse( parent );
box->setBorder( Box::Flat, QskRgb::RoyalBlue );
box->setBackground( type, QskRgb::FireBrick );
box->setTonalGradient( type, QskRgb::FireBrick );
}
}
@ -213,53 +236,60 @@ static void addRectangles9( QskLinearBox* parent )
box = new MyEllipse( parent );
box->setBorder( Box::Sunken1, borderTheme );
box->setGradient( QskGradient::Diagonal, Grey400, Grey500 );
box->setGradient( Box::Diagonal, Grey400, Grey500 );
box = new MyEllipse( parent );
box->setBorder( Box::Raised2, borderTheme );
box->setGradient( QskGradient::Vertical, Grey400, Grey500 );
box->setGradient( Box::Vertical, Grey400, Grey500 );
box = new MyEllipse( parent );
box->setBorder( Box::Raised2, borderTheme );
box->setGradient( QskGradient::Vertical, Lime200, Lime600 );
box->setGradient( Box::Vertical, Lime200, Lime600 );
box = new MyEllipse( parent );
box->setBorder( Box::Sunken2, borderTheme );
box->setGradient( QskGradient::Vertical, Lime600, Lime200 );
box->setGradient( Box::Vertical, Lime600, Lime200 );
}
static void addRectangles10( QskLinearBox* parent )
{
QColor borderTheme( "Indigo" );
using namespace QskRgb;
QColor borderTheme( Indigo );
// borderTheme.setAlpha( 100 );
QskGradientStops stops;
stops += QskGradientStop( 0.0, DeepPink );
stops += QskGradientStop( 0.5, DarkOrange );
stops += QskGradientStop( 1.0, HotPink );
Box* box;
box = new Box( parent );
box->setGradient( QskGradient::Horizontal, "DeepPink", "DarkOrange", "HotPink" );
box->setGradient( Box::Horizontal, stops );
box = new Box( parent );
box->setBorderWidth( 10 );
box->setBorderGradient( borderTheme );
box->setGradient( QskGradient::Diagonal, "DeepPink", "DarkOrange", "HotPink" );
box->setGradient( Box::Diagonal, stops );
box = new Box( parent );
box->setShape( 100, Qt::RelativeSize );
box->setBorderWidth( 5 );
box->setBorderGradient( borderTheme );
box->setGradient( QskGradient::Vertical, "DeepPink", "DarkOrange", "HotPink" );
box->setGradient( Box::Vertical, stops );
box = new Box( parent );
box->setShape( 100, Qt::RelativeSize );
box->setBorderWidth( 5 );
box->setBorderGradient( borderTheme );
box->setGradient( QskGradient::Diagonal, "DeepPink", "DarkOrange", "HotPink" );
box->setGradient( Box::Diagonal, stops );
box = new Box( parent );
box->setShape( 100, Qt::RelativeSize );
box->setBorderWidth( 5, 20, 30, 5 );
box->setBorderGradient( borderTheme );
box->setGradient( QskGradient::Vertical, "DeepPink", "DarkOrange", "HotPink" );
box->setGradient( Box::Vertical, stops );
}
static void addRectangles11( QskLinearBox* parent )
@ -279,111 +309,110 @@ static void addRectangles11( QskLinearBox* parent )
bw[ i - 1 ] = 0;
box->setBorderWidth( bw[ 0 ], bw[ 1 ], bw[ 2 ], bw[ 3 ] );
box->setBackground( fillType[ i ], QskRgb::Sienna, i >= 3 );
box->setTonalGradient( fillType[ i ], QskRgb::Sienna, i >= 3 );
}
}
static void addRectangles12( QskLinearBox* parent )
{
for ( auto orientation : { QskGradient::Vertical,
QskGradient::Horizontal, QskGradient::Diagonal } )
for ( auto fillType : { Box::Vertical, Box::Horizontal, Box::Diagonal } )
{
auto* box = new Box( parent );
box->setBorderWidth( 0 );
box->setGradient( orientation, QskRgb::LightSlateGray );
box->setTonalPalette( fillType, QskRgb::LightSlateGray );
}
for ( auto orientation : { QskGradient::Vertical, QskGradient::Diagonal } )
for ( auto fillType : { Box::Vertical, Box::Diagonal } )
{
auto* box = new Box( parent );
box->setBorder( Box::Flat, QskRgb::OrangeRed );
box->setGradient( orientation, QskRgb::DodgerBlue );
box->setTonalPalette( fillType, QskRgb::DodgerBlue );
}
for ( auto orientation : { QskGradient::Vertical,
QskGradient::Horizontal, QskGradient::Diagonal } )
for ( auto fillType : { Box::Vertical, Box::Horizontal, Box::Diagonal } )
{
auto* box = new Box( parent );
box->setBorderWidth( 0 );
box->setShape( 30, 40, Qt::RelativeSize );
box->setGradient( orientation, QskRgb::LightSlateGray );
box->setTonalPalette( fillType, QskRgb::LightSlateGray );
}
for ( auto orientation : { QskGradient::Vertical, QskGradient::Diagonal } )
for ( auto fillType : { Box::Vertical, Box::Diagonal } )
{
auto* box = new Box( parent );
box->setBorder( Box::Flat, QskRgb::OrangeRed );
box->setShape( 30, 40, Qt::RelativeSize );
box->setGradient( orientation, QskRgb::DodgerBlue );
box->setTonalPalette( fillType, QskRgb::DodgerBlue );
}
for ( auto orientation : { QskGradient::Vertical,
QskGradient::Horizontal, QskGradient::Diagonal } )
for ( auto fillType : { Box::Vertical, Box::Horizontal, Box::Diagonal } )
{
auto* box = new Box( parent );
box->setBorderWidth( 0 );
box->setShape( 100, 100, Qt::RelativeSize );
box->setGradient( orientation, QskRgb::LightSlateGray );
box->setTonalPalette( fillType, QskRgb::LightSlateGray );
}
for ( auto orientation : { QskGradient::Vertical, QskGradient::Diagonal } )
for ( auto fillType : { Box::Vertical, Box::Diagonal } )
{
auto* box = new Box( parent );
box->setBorder( Box::Flat, QskRgb::OrangeRed );
box->setShape( 100, 100, Qt::RelativeSize );
box->setGradient( orientation, QskRgb::DodgerBlue );
box->setTonalPalette( fillType, QskRgb::DodgerBlue );
}
}
static void addRectanglesRest( QskLinearBox* parent )
{
using namespace QskRgb;
Box* box;
box = new Box( parent );
box->setBorderWidth( 20, 0, 40, 0 );
box->setBorderGradient( { "DarkSeaGreen" } );
box->setBorderGradient( DarkSeaGreen );
box = new Box( parent );
box->setShape( 40, Qt::RelativeSize );
box->setBorderWidth( 20, 10, 30, 15 );
box->setBorderGradient( { "DarkOrange" } );
box->setGradient( QskGradient::Vertical, "LightSteelBlue", "SteelBlue" );
box->setBorderGradient( DarkOrange );
box->setGradient( Box::Vertical, LightSteelBlue, SteelBlue );
box = new Box( parent );
box->setBorderWidth( 20, 0, 10, 20 );
box->setBorderGradient( { "MediumSeaGreen" } );
box->setGradient( "DodgerBlue" );
box->setBorderGradient( MediumSeaGreen );
box->setGradient( DodgerBlue );
box = new Box( parent );
box->setShape( 20, Qt::AbsoluteSize );
box->setBorderWidth( 2, 10, 40, 2 );
box->setBorderGradient( { "Crimson" } );
box->setBorderGradient( Crimson );
box->setGradient( QskRgb::WhiteSmoke );
box = new Box( parent );
box->setShape( 100, Qt::RelativeSize );
box->setBorderWidth( 5, 20, 5, 0 );
box->setBorderGradient( { "CadetBlue" } );
box->setGradient( QskGradient::Vertical, "Gainsboro", "Seashell", "LightGray" );
box->setBorderGradient( { CadetBlue } );
box->setGradient( Box::Vertical, Gainsboro, Seashell, LightGray );
}
static void addColoredBorderRectangles1( QskLinearBox* parent, bool rounded, Box::FillType fillType )
static void addColoredBorderRectangles1( QskLinearBox* parent,
bool rounded, Box::FillType fillType )
{
auto* box = new Box( parent );
box->setBorderWidth( 20 );
QskGradient gradient1( Qt::Vertical, { { 0.0, Qt::blue },
{ 0.9, Qt::yellow },
{ 1.0, Qt::darkRed } } );
QskGradient gradient2( Qt::Vertical, { { 0.0, Qt::black },
{ 0.3, Qt::white },
{ 0.7, Qt::white },
{ 1.0, Qt::black } } );
QskGradient gradient3( Qt::green );
QskGradient gradient4( Qt::Vertical, Qt::magenta, Qt::cyan );
box->setBorderGradients( gradient1, gradient2, gradient3, gradient4 );
QskGradientStops stops[4];
stops[0] = { { 0.0, Qt::blue }, { 0.9, Qt::yellow }, { 1.0, Qt::darkRed } };
stops[1] = { { 0.0, Qt::black }, { 0.3, Qt::white }, { 0.7, Qt::white }, { 1.0, Qt::black } };
stops[2] = { { 0.0, Qt::green }, { 1.0, Qt::green } };
stops[3] = { { 0.0, Qt::magenta }, { 1.0, Qt::cyan } };
box->setBorderGradients( stops[0], stops[1], stops[2], stops[3] );
if( fillType != Box::Unfilled )
box->setBackground( fillType, QskRgb::CornflowerBlue );
box->setTonalGradient( fillType, QskRgb::CornflowerBlue );
if( rounded )
box->setShape( 30, Qt::AbsoluteSize );
@ -396,7 +425,7 @@ static void addColoredBorderRectangles2( QskLinearBox* parent, bool rounded, Box
box->setBorderGradients( Qt::red, Qt::green, Qt::blue, Qt::yellow );
if( fillType != Box::Unfilled )
box->setBackground( fillType, QskRgb::CornflowerBlue );
box->setTonalGradient( fillType, QskRgb::CornflowerBlue );
if( rounded )
box->setShape( 30, Qt::AbsoluteSize );
@ -406,26 +435,37 @@ static void addColoredBorderRectangles3( QskLinearBox* parent, bool rounded, Box
{
Box* box = new Box( parent );
box->setBorderWidth( 20 );
QskGradient gradient1( Qt::Vertical, { { 0.0, Qt::yellow },
{ 0.2, Qt::gray },
{ 0.6, Qt::magenta },
{ 1.0, Qt::green } } );
QskGradient gradient2( Qt::Vertical, { { 0.0, Qt::darkYellow },
{ 0.2, Qt::cyan },
{ 1.0, Qt::darkMagenta } } );
QskGradient gradient3( Qt::Vertical, { { 0.0, Qt::red },
{ 0.25, Qt::green },
{ 0.5, Qt::blue },
{ 0.75, Qt::magenta },
{ 1.0, Qt::cyan } } );
QskGradient gradient4( Qt::Vertical, { { 0.0, Qt::red },
{ 0.3, Qt::green },
{ 0.7, Qt::blue },
{ 1.0, Qt::cyan } } );
box->setBorderGradients( gradient3, gradient3, gradient3, gradient3 );
QskGradientStops stops[4];
stops[0] = {
{ 0.3, Qt::yellow },
{ 0.3, Qt::gray }, { 0.7, Qt::gray },
{ 0.7, Qt::green }
};
stops[1] = {
{ 0.3, Qt::darkYellow },
{ 0.3, Qt::cyan }, { 0.7, Qt::cyan },
{ 0.7, Qt::darkMagenta }
};
stops[2] = {
{ 0.3, Qt::red },
{ 0.3, Qt::blue }, { 0.7, Qt::blue },
{ 0.7, Qt::darkMagenta }
};
stops[3] = {
{ 0.3, Qt::darkYellow },
{ 0.3, Qt::darkRed }, { 0.7, Qt::darkRed },
{ 0.7, Qt::darkBlue }
};
box->setBorderGradients( stops[0], stops[1], stops[2], stops[3] );
if( fillType != Box::Unfilled )
box->setBackground( fillType, QskRgb::CornflowerBlue );
box->setTonalGradient( fillType, QskRgb::CornflowerBlue );
if( rounded )
box->setShape( 30, Qt::AbsoluteSize );
@ -435,11 +475,11 @@ static void addColoredBorderRectangles4( QskLinearBox* parent, bool rounded, Box
{
Box* box = new Box( parent );
box->setBorderWidth( 20 );
QskGradient gradient( Qt::Vertical, Qt::magenta, Qt::cyan );
box->setBorderGradients( gradient, gradient, gradient, gradient );
box->setBorderGradient( QskGradient( Qt::magenta, Qt::cyan ) );
if( fillType != Box::Unfilled )
box->setBackground( fillType, QskRgb::CornflowerBlue );
box->setTonalGradient( fillType, QskRgb::CornflowerBlue );
if( rounded )
box->setShape( 30, Qt::AbsoluteSize );
@ -449,14 +489,14 @@ static void addColoredBorderRectangles5( QskLinearBox* parent, bool rounded, Box
{
Box* box = new Box( parent );
box->setBorderWidth( 20 );
QskGradient gradient( Qt::Vertical, { { 0.0, Qt::black },
{ 0.3, Qt::white },
{ 0.7, Qt::white },
{ 1.0, Qt::black } } );
box->setBorderGradients( gradient, gradient, gradient, gradient );
const QskGradientStops stops = { { 0.0, Qt::black }, { 0.3, Qt::white },
{ 0.7, Qt::white }, { 1.0, Qt::black } };
box->setBorderGradient( stops );
if( fillType != Box::Unfilled )
box->setBackground( fillType, QskRgb::CornflowerBlue );
box->setTonalGradient( fillType, QskRgb::CornflowerBlue );
if( rounded )
box->setShape( { 10, 20, 20, 40 } );

View File

@ -6,8 +6,8 @@ Qsk.PushButton
sizePolicy
{
// avoid the effect of long texts
horizontalPolicy: Qsk.SizePolicy.Ignored
verticalPolicy: Qsk.SizePolicy.Ignored
horizontal: Qsk.SizePolicy.Ignored
vertical: Qsk.SizePolicy.Ignored
}
minimumSize

View File

@ -7,13 +7,13 @@
#include <SkinnyShortcut.h>
#include <QskAspect.h>
#include <QskGradient.h>
#include <QskGraphicLabel.h>
#include <QskObjectCounter.h>
#include <QskShortcutMap.h>
#include <QskSubWindow.h>
#include <QskSubWindowArea.h>
#include <QskWindow.h>
#include <QskRgbValue.h>
#include <QDebug>
#include <QGuiApplication>
@ -57,9 +57,11 @@ int main( int argc, char* argv[] )
SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts );
QskGradient gradient( QskRgb::DarkSlateGray, QskRgb::LightSlateGray );
gradient.setLinearDirection( 0.0, 0.0, 1.0, 1.0 );
QskSubWindowArea* area = new QskSubWindowArea();
area->setGradientHint( QskSubWindowArea::Panel,
QskGradient( QskGradient::Diagonal, "DarkSlateGray", "LightSlateGray" ) );
area->setGradientHint( QskSubWindowArea::Panel, gradient );
QRectF windowRect( 0, 0, 250, 250 );

View File

@ -7,9 +7,8 @@
#include <QskBoxBorderColors.h>
#include <QskBoxBorderMetrics.h>
#include <QskBoxNode.h>
#include <QskBoxRectangleNode.h>
#include <QskBoxShapeMetrics.h>
#include <QskGradient.h>
#include <QskSGNode.h>
static inline qreal effectiveRadius( const QRectF& rect, qreal percentage )
@ -99,7 +98,7 @@ void Frame::updateNode( QSGNode* parentNode )
const quint8 nodeRole = 0;
auto node = static_cast< QskBoxNode* >(
auto node = static_cast< QskBoxRectangleNode* >(
QskSGNode::findChildNode( parentNode, nodeRole ) );
const QRectF rect = contentsRect();
@ -111,7 +110,7 @@ void Frame::updateNode( QSGNode* parentNode )
if ( node == nullptr )
{
node = new QskBoxNode;
node = new QskBoxRectangleNode;
QskSGNode::setNodeRole( node, nodeRole );
}
@ -121,7 +120,7 @@ void Frame::updateNode( QSGNode* parentNode )
parentNode->appendChildNode( node );
}
void Frame::updateFrameNode( const QRectF& rect, QskBoxNode* node )
void Frame::updateFrameNode( const QRectF& rect, QskBoxRectangleNode* node )
{
const QColor dark = m_color.darker( 150 );
const QColor light = m_color.lighter( 150 );
@ -151,7 +150,7 @@ void Frame::updateFrameNode( const QRectF& rect, QskBoxNode* node )
const QskBoxBorderColors borderColors( c1, c1, c2, c2 );
const qreal radius = effectiveRadius( rect, m_radius );
node->setBoxData( rect, radius, m_frameWidth, borderColors, m_color );
node->updateNode( rect, radius, m_frameWidth, borderColors, m_color );
}
#include "moc_Frame.cpp"

View File

@ -7,7 +7,7 @@
#include "QskControl.h"
class QskBoxNode;
class QskBoxRectangleNode;
class Frame : public QskControl
{
@ -62,7 +62,7 @@ class Frame : public QskControl
void updateNode( QSGNode* ) override;
private:
void updateFrameNode( const QRectF&, QskBoxNode* );
void updateFrameNode( const QRectF&, QskBoxRectangleNode* );
Style m_style;
QColor m_color;

View File

@ -30,7 +30,6 @@ namespace
void populate()
{
const char* texts[] = { "Press Me", "Check Me" };
const char* graphics[] = { "diamond/khaki", "ellipse/sandybrown" };
for ( int i = 0; i < 6; i++ )
{
@ -42,7 +41,7 @@ namespace
if ( i > 1 )
{
auto src = QStringLiteral( "image://shapes/" ) + graphics[ index ];
auto src = QStringLiteral( "plus" );
button->setGraphicSource( src );
}
@ -84,7 +83,7 @@ namespace
{
public:
CheckButtonBox( QQuickItem* parent = nullptr )
: QskLinearBox( Qt::Horizontal, parent )
: QskLinearBox( Qt::Horizontal, 2, parent )
{
setSpacing( 40 );
setExtraSpacingAt( Qt::LeftEdge | Qt::RightEdge | Qt::BottomEdge );
@ -94,6 +93,9 @@ namespace
auto button2 = new QskCheckBox( "Options 2", this );
button2->setLayoutMirroring( true );
auto button3 = new QskCheckBox( "Error", this );
button3->setSkinStateFlag( QskCheckBox::Error );
}
};
}

View File

@ -48,3 +48,6 @@ HEADERS += \
SOURCES += \
Page.cpp \
main.cpp
RESOURCES += \
icons.qrc \

View File

@ -0,0 +1,9 @@
<RCC>
<qresource>
<file>icons/qvg/airport_shuttle.qvg</file>
<file>icons/qvg/flight.qvg</file>
<file>icons/qvg/local_pizza.qvg</file>
<file>icons/qvg/plus.qvg</file>
<file>icons/qvg/sports_soccer.qvg</file>
</qresource>
</RCC>

View File

@ -0,0 +1,4 @@
<svg width="23" height="15" viewBox="0 0 23 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.5 14.5C4.66667 14.5 3.95833 14.2083 3.375 13.625C2.79167 13.0417 2.5 12.3333 2.5 11.5H0.5V2.5C0.5 1.95 0.696 1.47933 1.088 1.088C1.47933 0.696 1.95 0.5 2.5 0.5H16.5L22.5 6.5V11.5H20.5C20.5 12.3333 20.2083 13.0417 19.625 13.625C19.0417 14.2083 18.3333 14.5 17.5 14.5C16.6667 14.5 15.9583 14.2083 15.375 13.625C14.7917 13.0417 14.5 12.3333 14.5 11.5H8.5C8.5 12.3333 8.20833 13.0417 7.625 13.625C7.04167 14.2083 6.33333 14.5 5.5 14.5ZM14.5 5.5H18.5L15.5 2.5H14.5V5.5ZM8.5 5.5H12.5V2.5H8.5V5.5ZM2.5 5.5H6.5V2.5H2.5V5.5ZM5.5 12.75C5.85 12.75 6.146 12.629 6.388 12.387C6.62933 12.1457 6.75 11.85 6.75 11.5C6.75 11.15 6.62933 10.8543 6.388 10.613C6.146 10.371 5.85 10.25 5.5 10.25C5.15 10.25 4.85433 10.371 4.613 10.613C4.371 10.8543 4.25 11.15 4.25 11.5C4.25 11.85 4.371 12.1457 4.613 12.387C4.85433 12.629 5.15 12.75 5.5 12.75ZM17.5 12.75C17.85 12.75 18.146 12.629 18.388 12.387C18.6293 12.1457 18.75 11.85 18.75 11.5C18.75 11.15 18.6293 10.8543 18.388 10.613C18.146 10.371 17.85 10.25 17.5 10.25C17.15 10.25 16.8543 10.371 16.613 10.613C16.371 10.8543 16.25 11.15 16.25 11.5C16.25 11.85 16.371 12.1457 16.613 12.387C16.8543 12.629 17.15 12.75 17.5 12.75ZM2.5 9.5H3.3C3.58333 9.2 3.90833 8.95833 4.275 8.775C4.64167 8.59167 5.05 8.5 5.5 8.5C5.95 8.5 6.35833 8.59167 6.725 8.775C7.09167 8.95833 7.41667 9.2 7.7 9.5H15.3C15.5833 9.2 15.9083 8.95833 16.275 8.775C16.6417 8.59167 17.05 8.5 17.5 8.5C17.95 8.5 18.3583 8.59167 18.725 8.775C19.0917 8.95833 19.4167 9.2 19.7 9.5H20.5V7.5H2.5V9.5Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,4 @@
<svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7 20.5V19L9 17.5V12L0.5 14.5V12.5L9 7.5V2C9 1.58333 9.146 1.22933 9.438 0.938C9.72933 0.646 10.0833 0.5 10.5 0.5C10.9167 0.5 11.2707 0.646 11.562 0.938C11.854 1.22933 12 1.58333 12 2V7.5L20.5 12.5V14.5L12 12V17.5L14 19V20.5L10.5 19.5L7 20.5Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 372 B

View File

@ -0,0 +1,4 @@
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.5037 19.5037L0.503679 4.50368C1.92035 3.30368 3.47468 2.33701 5.16668 1.60368C6.85801 0.870346 8.63701 0.503679 10.5037 0.503679C12.3703 0.503679 14.1493 0.866346 15.8407 1.59168C17.5327 2.31635 19.087 3.28701 20.5037 4.50368L10.5037 19.5037ZM10.5037 15.9037L17.8037 4.95368C16.7203 4.20368 15.562 3.60768 14.3287 3.16568C13.0953 2.72435 11.8203 2.50368 10.5037 2.50368C9.18701 2.50368 7.91635 2.72435 6.69168 3.16568C5.46635 3.60768 4.30368 4.20368 3.20368 4.95368L10.5037 15.9037ZM8.00368 7.50368C8.42035 7.50368 8.77435 7.35768 9.06568 7.06568C9.35768 6.77435 9.50368 6.42035 9.50368 6.00368C9.50368 5.58701 9.35768 5.23301 9.06568 4.94168C8.77435 4.64968 8.42035 4.50368 8.00368 4.50368C7.58701 4.50368 7.23301 4.64968 6.94168 4.94168C6.64968 5.23301 6.50368 5.58701 6.50368 6.00368C6.50368 6.42035 6.64968 6.77435 6.94168 7.06568C7.23301 7.35768 7.58701 7.50368 8.00368 7.50368ZM10.5037 12.5037C10.9203 12.5037 11.2743 12.3577 11.5657 12.0657C11.8577 11.7743 12.0037 11.4203 12.0037 11.0037C12.0037 10.587 11.8577 10.233 11.5657 9.94168C11.2743 9.64968 10.9203 9.50368 10.5037 9.50368C10.087 9.50368 9.73301 9.64968 9.44168 9.94168C9.14968 10.233 9.00368 10.587 9.00368 11.0037C9.00368 11.4203 9.14968 11.7743 9.44168 12.0657C9.73301 12.3577 10.087 12.5037 10.5037 12.5037Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,4 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 6.75H6.75V12H5.25V6.75H0V5.25H5.25V0H6.75V5.25H12V6.75Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 189 B

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,4 @@
<svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.5 20.5C9.11667 20.5 7.81667 20.2373 6.6 19.712C5.38333 19.1873 4.325 18.475 3.425 17.575C2.525 16.675 1.81267 15.6167 1.288 14.4C0.762667 13.1833 0.5 11.8833 0.5 10.5C0.5 9.11667 0.762667 7.81667 1.288 6.6C1.81267 5.38333 2.525 4.325 3.425 3.425C4.325 2.525 5.38333 1.81233 6.6 1.287C7.81667 0.762333 9.11667 0.5 10.5 0.5C11.8833 0.5 13.1833 0.762333 14.4 1.287C15.6167 1.81233 16.675 2.525 17.575 3.425C18.475 4.325 19.1873 5.38333 19.712 6.6C20.2373 7.81667 20.5 9.11667 20.5 10.5C20.5 11.8833 20.2373 13.1833 19.712 14.4C19.1873 15.6167 18.475 16.675 17.575 17.575C16.675 18.475 15.6167 19.1873 14.4 19.712C13.1833 20.2373 11.8833 20.5 10.5 20.5ZM15.5 8L16.85 7.55L17.25 6.2C16.7167 5.4 16.075 4.71233 15.325 4.137C14.575 3.56233 13.75 3.13333 12.85 2.85L11.5 3.8V5.2L15.5 8ZM5.5 8L9.5 5.2V3.8L8.15 2.85C7.25 3.13333 6.425 3.56233 5.675 4.137C4.925 4.71233 4.28333 5.4 3.75 6.2L4.15 7.55L5.5 8ZM4.45 15.7L5.6 15.6L6.35 14.25L4.9 9.9L3.5 9.4L2.5 10.15C2.5 11.2333 2.65 12.2207 2.95 13.112C3.25 14.004 3.75 14.8667 4.45 15.7ZM10.5 18.5C10.9333 18.5 11.3583 18.4667 11.775 18.4C12.1917 18.3333 12.6 18.2333 13 18.1L13.7 16.6L13.05 15.5H7.95L7.3 16.6L8 18.1C8.4 18.2333 8.80833 18.3333 9.225 18.4C9.64167 18.4667 10.0667 18.5 10.5 18.5ZM8.25 13.5H12.75L14.15 9.5L10.5 6.95L6.9 9.5L8.25 13.5ZM16.55 15.7C17.25 14.8667 17.75 14.004 18.05 13.112C18.35 12.2207 18.5 11.2333 18.5 10.15L17.5 9.45L16.1 9.9L14.65 14.25L15.4 15.6L16.55 15.7Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -29,15 +29,13 @@ namespace
{
const QskHctColor hctColor( base );
QVector< QRgb > rgb;
rgb += hctColor.toned( 75 ).rgb();
rgb += hctColor.toned( 60 ).rgb();
rgb += hctColor.toned( 45 ).rgb();
rgb += hctColor.toned( 30 ).rgb();
QVector< QRgb > colors;
colors += hctColor.toned( 75 ).rgb();
colors += hctColor.toned( 60 ).rgb();
colors += hctColor.toned( 45 ).rgb();
colors += hctColor.toned( 30 ).rgb();
const auto stops = QskGradient::colorStops( rgb, true );
setBarGradient( QskGradient( orientation(), stops ) );
setBarGradient( qskBuildGradientStops( colors, true ) );
}
};
}

View File

@ -19,31 +19,33 @@ namespace
orientation = ( orientation == Qt::Horizontal )
? Qt::Vertical : Qt::Horizontal;
const char* texts[] =
{
"airport",
"flight",
"pizza",
"soccer"
};
{
auto bar = new QskSegmentedBar( orientation, this );
bar->addText( "Option 1" );
bar->addText( "Option 2" );
bar->addText( "Option 3" );
bar->addText( "Option 4" );
for ( const auto text: texts )
bar->addOption( {}, text );
}
{
const auto prefix = QStringLiteral( "image://shapes/" );
const char* icons[] =
{
"rectangle/crimson",
"triangleright/thistle",
"ellipse/khaki",
"ring/sandybrown",
"star/darkviolet",
"hexagon/darkslategray"
"airport_shuttle",
"flight",
"local_pizza",
"sports_soccer"
};
auto bar = new QskSegmentedBar( orientation, this );
for ( const auto icon : icons )
bar->addGraphic( prefix + icon );
for ( uint i = 0; i < sizeof( icons ) / sizeof( icons[ 0 ] ); ++i )
bar->addOption( QUrl( QString( icons[ i ] ) ), texts[ i ] );
}
setExtraSpacingAt( Qt::LeftEdge | Qt::BottomEdge );

View File

@ -34,7 +34,7 @@ Qsk.Window
{
source: modelData
sourceSize.width: 100 // width according to aspect ratio
graphicStrutSize.width: 100 // height: according to aspect ratio
fillMode: Qsk.GraphicLabel.PreserveAspectFit
alignment: Qt.AlignCenter
//mirror: true

View File

@ -19,6 +19,8 @@ namespace
{
class UpAndDownBox : public QskLinearBox
{
Q_OBJECT
public:
UpAndDownBox( QQuickItem* parent )
: QskLinearBox( Qt::Vertical, parent )
@ -26,15 +28,25 @@ namespace
setSizePolicy( Qt::Horizontal, QskSizePolicy::Fixed );
setSpacing( 0 );
new RoundButton( QskAspect::Top, this );
new RoundButton( QskAspect::Bottom, this );
auto* const topButton = new RoundButton( QskAspect::Top, this );
connect( topButton, &QskPushButton::clicked, this, &UpAndDownBox::increase );
auto* const bottomButton = new RoundButton( QskAspect::Bottom, this );
connect( bottomButton, &QskPushButton::clicked, this, &UpAndDownBox::decrease );
}
Q_SIGNALS:
void increase();
void decrease();
};
}
BoxWithButtons::BoxWithButtons( const QString& title, const QString& value,
bool isBright, QQuickItem* parent )
BoxWithButtons::BoxWithButtons( const QString& title, const QString &prefix,
const int initialValue, const QString &suffix,
bool isBright, QQuickItem* parent )
: Box( QString(), parent )
, m_prefix( prefix )
, m_suffix( suffix )
{
setSubcontrolProxy( QskBox::Panel, Panel );
@ -44,7 +56,8 @@ BoxWithButtons::BoxWithButtons( const QString& title, const QString& value,
layout->setSpacing( 20 );
auto iconLabel = new RoundedIcon( isBright, layout );
iconLabel->setSource( title );
iconLabel->setGraphicSource( title );
iconLabel->setGraphicStrutSize( { 35.17, 35.17 } );
iconLabel->setFixedSize( 68, 68 );
auto titleAndValue = new QskLinearBox( Qt::Vertical, layout );
@ -54,10 +67,30 @@ BoxWithButtons::BoxWithButtons( const QString& title, const QString& value,
auto* titleLabel = new QskTextLabel( title, titleAndValue );
titleLabel->setFontRole( Skin::TitleFont );
auto valueLabel = new QskTextLabel( value, titleAndValue );
valueLabel->setSubcontrolProxy( QskTextLabel::Text, ValueText );
m_valueLabel = new QskTextLabel( titleAndValue );
m_valueLabel->setSubcontrolProxy( QskTextLabel::Text, ValueText );
setValue( initialValue );
layout->addStretch( 1 );
new UpAndDownBox( layout );
auto* const upAndDownBox = new UpAndDownBox( layout );
connect( upAndDownBox, &UpAndDownBox::increase, this, [this]()
{
setValue( m_value + 1 );
} );
connect( upAndDownBox, &UpAndDownBox::decrease, this, [this]()
{
setValue( m_value - 1 );
} );
}
void BoxWithButtons::setValue( const int value )
{
m_value = qBound( 0, value, 100 );
const QString text = m_prefix + QString::number( m_value ) + m_suffix;
m_valueLabel->setText( text );
}
#include "BoxWithButtons.moc"

View File

@ -7,11 +7,22 @@
#include "Box.h"
class QskTextLabel;
class BoxWithButtons : public Box
{
public:
QSK_SUBCONTROLS( Panel, ValuePanel, ValueText )
BoxWithButtons( const QString& title, const QString& value,
bool isBright, QQuickItem* parent = nullptr );
BoxWithButtons( const QString& title, const QString& prefix,
const int initialValue, const QString& suffix,
bool isBright, QQuickItem* parent = nullptr );
private:
void setValue( const int value );
const QString m_prefix;
int m_value;
const QString m_suffix;
QskTextLabel* m_valueLabel;
};

View File

@ -6,7 +6,6 @@
#include "CircularProgressBar.h"
#include <QskAnimator.h>
#include <QskArcMetrics.h>
#include <QskFunctions.h>
QSK_SUBCONTROL( CircularProgressBar, Groove )
@ -75,6 +74,8 @@ class CircularProgressBar::PrivateData
bool isIndeterminate = false;
};
CircularProgressBar::~CircularProgressBar() = default;
CircularProgressBar::CircularProgressBar( qreal min, qreal max, QQuickItem* parent )
: QskBoundedControl( min, max, parent )
, m_data( new PrivateData )

View File

@ -6,9 +6,6 @@
#pragma once
#include <QskBoundedControl.h>
#include <QskGradient.h>
#include <QGradient>
class CircularProgressBar : public QskBoundedControl
{
@ -31,6 +28,7 @@ class CircularProgressBar : public QskBoundedControl
CircularProgressBar( qreal min, qreal max, QQuickItem* parent = nullptr );
CircularProgressBar( QQuickItem* parent = nullptr );
~CircularProgressBar();
bool isIndeterminate() const;
void setIndeterminate( bool on = true );

View File

@ -11,7 +11,6 @@
#include "LightDisplay.h"
#include "GridBox.h"
#include "MyDevices.h"
#include "PieChart.h"
#include "TopBar.h"
#include "UsageBox.h"
@ -34,7 +33,7 @@ namespace
{
public:
IndoorTemperature( QQuickItem* parent = nullptr )
: BoxWithButtons( "Indoor Temperature", "+24", true, parent )
: BoxWithButtons( "Indoor Temperature", "+", 24, {}, true, parent )
{
}
};
@ -43,7 +42,7 @@ namespace
{
public:
Humidity( QQuickItem* parent = nullptr )
: BoxWithButtons( "Humidity", "30%", false, parent )
: BoxWithButtons( "Humidity", {}, 30, "%", false, parent )
{
}
};

View File

@ -0,0 +1,21 @@
/******************************************************************************
* Copyright (C) 2021 Edelhirsch Software GmbH
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#include "DevicesPage.h"
#include <QskSkin.h>
#include <QskTextLabel.h>
QSK_SUBCONTROL( DevicesPage, Panel )
DevicesPage::DevicesPage( QQuickItem* parent )
: QskLinearBox( Qt::Vertical, parent )
{
auto* const textLabel = new QskTextLabel( "devices page", this );
textLabel->setAlignmentHint( QskTextLabel::Text, Qt::AlignCenter );
textLabel->setFontRole( QskSkin::HugeFont );
}
#include "moc_DevicesPage.cpp"

View File

@ -0,0 +1,19 @@
/******************************************************************************
* Copyright (C) 2021 Edelhirsch Software GmbH
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#pragma once
#include <QskGridBox.h>
#include <QskLinearBox.h>
class DevicesPage : public QskLinearBox
{
Q_OBJECT
public:
QSK_SUBCONTROLS( Panel )
DevicesPage( QQuickItem* parent );
};

View File

@ -10,7 +10,7 @@
#include <QskBoxBorderColors.h>
#include <QskBoxBorderMetrics.h>
#include <QskBoxNode.h>
#include <QskBoxRectangleNode.h>
#include <QskBoxShapeMetrics.h>
namespace
@ -98,8 +98,6 @@ QSGNode* DiagramSkinlet::updateChartNode( const Diagram* diagram, QSGNode* node
const QRectF rect = diagram->subControlRect( Q::Chart );
const qreal yMax = diagram->yMax();
const QVector< Diagram::Type > types = { Diagram::Line, Diagram::Area, Diagram::Bar };
for( int i = 0; i < diagram->dataPoints().size(); ++i )
{
QSGNode* chartNode;
@ -122,10 +120,8 @@ QSGNode* DiagramSkinlet::updateChartNode( const Diagram* diagram, QSGNode* node
int lineWidth = diagram->metric( lineSubcontrol | QskAspect::Size );
for( int j = 0; j < types.size(); ++j )
for( const auto type : { Diagram::Line, Diagram::Area, Diagram::Bar } )
{
const auto type = types.at( j );
if( diagram->typesAt( i ) & type )
{
QColor color;
@ -146,15 +142,15 @@ QSGNode* DiagramSkinlet::updateChartNode( const Diagram* diagram, QSGNode* node
for( int k = 0; k < dataPoints.size(); ++k )
{
QskBoxNode* barNode;
QskBoxRectangleNode* barNode;
if( barsNode->childCount() > k )
{
barNode = static_cast< QskBoxNode* >( barsNode->childAtIndex( k ) );
barNode = static_cast< QskBoxRectangleNode* >( barsNode->childAtIndex( k ) );
}
else
{
barNode = new QskBoxNode;
barNode = new QskBoxRectangleNode;
barsNode->appendChildNode( barNode );
}
@ -176,7 +172,7 @@ QSGNode* DiagramSkinlet::updateChartNode( const Diagram* diagram, QSGNode* node
color = diagram->color( barSubcontrol );
const auto shape = diagram->boxShapeHint( barSubcontrol );
barNode->setBoxData( barRect, shape, {}, {}, color );
barNode->updateNode( barRect, shape, {}, {}, color );
}
}
else
@ -208,9 +204,8 @@ QSGNode* DiagramSkinlet::updateChartNode( const Diagram* diagram, QSGNode* node
dataPointNode->update( rect, nodeType, color, dataPoints, yMax, false, lineWidth );
}
nodeIndex++;
}
nodeIndex++;
}
while( nodeIndex < chartNode->childCount() )

View File

@ -3,23 +3,18 @@
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#include "PieChartPainted.h"
#include "EnergyMeter.h"
#include "CircularProgressBar.h"
#include <QskAnimator.h>
#include <QskBox.h>
#include <QskRgbValue.h>
#include <QskSetup.h>
#include <QskSkin.h>
#include <QskTextLabel.h>
#include <QskFunctions.h>
#include <QskSkin.h>
namespace
{
class ProgressLabel : public QskTextLabel
class ValueLabel : public QskTextLabel
{
public:
ProgressLabel( QQuickItem* parent )
ValueLabel( QQuickItem* parent )
: QskTextLabel( parent )
{
initSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed );
@ -34,22 +29,22 @@ namespace
};
}
PieChartPainted::PieChartPainted( const QColor& textColor, const QskGradient& gradient,
int progress, QQuickItem* parent )
EnergyMeter::EnergyMeter( const QColor& textColor,
const QskGradient& gradient, int value, QQuickItem* parent )
: QskControl( parent )
{
setAutoLayoutChildren( true );
auto progressBar = new CircularProgressBar( this );
progressBar->setGradientHint( CircularProgressBar::Bar, gradient );
progressBar->setValue( progress );
auto valueBar = new CircularProgressBar( this );
valueBar->setGradientHint( CircularProgressBar::Bar, gradient );
valueBar->setValue( value );
auto progressLabel = new ProgressLabel( this );
progressLabel->setTextColor( textColor );
progressLabel->setValue( progress );
auto valueLabel = new ValueLabel( this );
valueLabel->setTextColor( textColor );
valueLabel->setValue( value );
}
QSizeF PieChartPainted::contentsSizeHint(
QSizeF EnergyMeter::contentsSizeHint(
Qt::SizeHint which, const QSizeF& constraint ) const
{
if ( which != Qt::PreferredSize )

View File

@ -7,10 +7,10 @@
#include <QskControl.h>
class PieChartPainted : public QskControl
class EnergyMeter : public QskControl
{
public:
PieChartPainted( const QColor&, const QskGradient&,
EnergyMeter( const QColor&, const QskGradient&,
int progress, QQuickItem* parent = nullptr );
protected:

View File

@ -6,10 +6,8 @@
#include "GraphicProvider.h"
#include <QskGraphic.h>
#include <QskGraphicIO.h>
#include <QSvgRenderer>
#include <QPainter>
#include <QImage>
#include <QFile>
const inline QString pathName( const QString& baseName, const QString& suffix )
@ -23,7 +21,7 @@ const inline QString pathName( const QString& baseName, const QString& suffix )
const QskGraphic* GraphicProvider::loadGraphic( const QString& id ) const
{
static QString scope = QStringLiteral( ":/images/" );
static QString scope = QStringLiteral( ":/images/qvg/" );
QString baseName = scope;
baseName += id.toLower().replace( ' ', '-' );
@ -31,30 +29,12 @@ const QskGraphic* GraphicProvider::loadGraphic( const QString& id ) const
auto path = pathName( baseName, QString() );
if ( path.isEmpty() )
path = pathName( baseName, ".png" );
if ( path.isEmpty() )
path = pathName( baseName, ".svg" );
path = pathName( baseName, ".qvg" );
QskGraphic graphic;
if ( !path.isEmpty() )
{
if ( path.endsWith( ".png" ) )
{
graphic = QskGraphic::fromImage( QImage( path ) );
}
else
{
QSvgRenderer renderer;
if ( renderer.load( path ) )
{
QPainter painter( &graphic );
renderer.render( &painter );
painter.end();
}
}
}
graphic = QskGraphicIO::read( path );
return graphic.isNull() ? nullptr : new QskGraphic( graphic );
}

View File

@ -43,10 +43,6 @@ LightDisplay::LightDisplay( QQuickItem* parent )
setAlignmentHint( ValueText, Qt::AlignRight );
setBoundaries( 0, 100 );
// ### move to Skin:
setShadow( { 0, 20 } );
setShadowColor( 0xe5e5e5 );
}
bool LightDisplay::isPressed() const
@ -54,17 +50,6 @@ bool LightDisplay::isPressed() const
return hasSkinState( Pressed );
}
void LightDisplay::setShadow( const QskShadowMetrics& shadow )
{
m_shadow = shadow;
update();
}
const QskShadowMetrics& LightDisplay::shadow() const
{
return m_shadow;
}
void LightDisplay::setGradient( const QskGradient& gradient )
{
m_gradient = gradient;
@ -76,17 +61,6 @@ const QskGradient& LightDisplay::gradient() const
return m_gradient;
}
void LightDisplay::setShadowColor( const QColor& color )
{
m_shadowColor = color;
update();
}
QColor LightDisplay::shadowColor() const
{
return m_shadowColor;
}
void LightDisplay::mousePressEvent( QMouseEvent* event )
{
QRectF handleRect = subControlRect( LightDisplay::Knob );
@ -117,7 +91,7 @@ void LightDisplay::mouseMoveEvent( QMouseEvent* event )
return;
}
const QskArcMetrics metrics = arcMetricsHint( ColdAndWarmArc );
const auto metrics = arcMetricsHint( ColdAndWarmArc );
qreal angle = angleFromPoint( rect, mousePos );
const int tolerance = 20;
@ -161,7 +135,7 @@ bool LightDisplay::arcContainsPoint( const QRectF& rect, const QPointF& point )
// putting this in an own function just because it might be useful
// at other places in the future
const QskArcMetrics metrics = arcMetricsHint( ColdAndWarmArc );
const auto metrics = arcMetricsHint( ColdAndWarmArc );
const int tolerance = 20;
// 1. check angle

View File

@ -22,15 +22,9 @@ class LightDisplay : public QskBoundedValueInput
bool isPressed() const;
void setShadow( const QskShadowMetrics& );
const QskShadowMetrics& shadow() const;
void setGradient( const QskGradient& );
const QskGradient& gradient() const;
void setShadowColor( const QColor& );
QColor shadowColor() const;
protected:
void mousePressEvent( QMouseEvent* e ) override;
void mouseMoveEvent( QMouseEvent* e ) override;

View File

@ -37,8 +37,8 @@ QRectF LightDisplaySkinlet::subControlRect( const QskSkinnable* skinnable,
if( subControl == LightDisplay::Groove || subControl == LightDisplay::Panel )
{
QSizeF textSize = textLabelsSize( display );
QskArcMetrics arcMetrics = display->arcMetricsHint( LightDisplay::ColdAndWarmArc );
const auto textSize = textLabelsSize( display );
const auto arcMetrics = display->arcMetricsHint( LightDisplay::ColdAndWarmArc );
const qreal ticksWidth = display->arcMetricsHint( LightDisplay::Tickmarks ).width() + ticksSpacing;
const qreal x = textSize.width() + arcMetrics.width() + ticksWidth;
@ -81,7 +81,7 @@ QRectF LightDisplaySkinlet::subControlRect( const QskSkinnable* skinnable,
else if( subControl == LightDisplay::LeftLabel )
{
const QRectF ticksRect = subControlRect( skinnable, contentsRect, LightDisplay::Tickmarks );
QSizeF size = textLabelsSize( display );
const auto size = textLabelsSize( display );
rect.setWidth( size.width() );
@ -92,8 +92,8 @@ QRectF LightDisplaySkinlet::subControlRect( const QskSkinnable* skinnable,
}
else if( subControl == LightDisplay::RightLabel )
{
QRectF ticksRect = subControlRect( skinnable, contentsRect, LightDisplay::Tickmarks );
QSizeF size = textLabelsSize( display );
const auto ticksRect = subControlRect( skinnable, contentsRect, LightDisplay::Tickmarks );
const auto size = textLabelsSize( display );
rect.setX( ticksRect.x() + ticksRect.width() );
@ -104,9 +104,9 @@ QRectF LightDisplaySkinlet::subControlRect( const QskSkinnable* skinnable,
}
else if( subControl == LightDisplay::Knob )
{
QRectF arcRect = subControlRect( skinnable, contentsRect, LightDisplay::ColdAndWarmArc );
QskArcMetrics arcMetrics = display->arcMetricsHint( LightDisplay::ColdAndWarmArc );
QSizeF knobSize = display->strutSizeHint( LightDisplay::Knob );
const auto arcRect = subControlRect( skinnable, contentsRect, LightDisplay::ColdAndWarmArc );
const auto arcMetrics = display->arcMetricsHint( LightDisplay::ColdAndWarmArc );
const auto knobSize = display->strutSizeHint( LightDisplay::Knob );
const qreal radius = ( arcRect.width() - arcMetrics.width() ) / 2;
const qreal angle = display->valueAsRatio() * 180;
@ -137,18 +137,7 @@ QSGNode* LightDisplaySkinlet::updateSubNode(
}
case GrooveRole:
{
const QRectF grooveRect = display->subControlRect( LightDisplay::Groove );
if ( grooveRect.isEmpty() )
return nullptr;
const auto& shadowMetrics = display->shadow();
const auto shadowRect = shadowMetrics.shadowRect( grooveRect );
auto shadowNode = QskSGNode::ensureNode< QskBoxShadowNode >( node );
shadowNode->setShadowData( shadowRect, grooveRect.width() / 2,
shadowMetrics.blurRadius(), display->shadowColor() );
return shadowNode;
return updateBoxNode( skinnable, node, LightDisplay::Groove );
}
case ColdAndWarmArcRole:
{

View File

@ -1,8 +1,12 @@
#include "MainItem.h"
#include "DashboardPage.h"
#include "DevicesPage.h"
#include "MenuBar.h"
#include "MembersPage.h"
#include "RoomsPage.h"
#include "StatisticsPage.h"
#include "StoragePage.h"
#include <QskGesture.h>
#include <QskEvent.h>
@ -12,13 +16,120 @@
#include <QQuickFramebufferObject>
#include <QGuiApplication>
#include <QQuickWindow>
#include <QtMath>
#include <QTimer>
QPair< Cube::Position, Cube::Edge > Cube::s_neighbors[ Cube::NumPositions ][ Cube::NumEdges ] =
{
// neighbors of Left side:
{
{ Cube::BackPos, Cube::BottomEdge }, // going Left
{ Cube::FrontPos, Cube::BottomEdge }, // going Right
{ Cube::TopPos, Cube::LeftEdge }, // going Top
{ Cube::BottomPos, Cube::RightEdge } // going Bottom
},
// Right:
{
{ Cube::FrontPos, Cube::BottomEdge },
{ Cube::BackPos, Cube::BottomEdge },
{ Cube::TopPos, Cube::RightEdge },
{ Cube::BottomPos, Cube::LeftEdge }
},
// Top:
{
{ Cube::LeftPos, Cube::RightEdge },
{ Cube::RightPos, Cube::LeftEdge },
{ Cube::BackPos, Cube::TopEdge },
{ Cube::FrontPos, Cube::BottomEdge }
},
// Bottom:
{
{ Cube::LeftPos, Cube::LeftEdge },
{ Cube::RightPos, Cube::RightEdge },
{ Cube::FrontPos, Cube::BottomEdge },
{ Cube::BackPos, Cube::TopEdge }
},
// Front:
{
{ Cube::LeftPos, Cube::BottomEdge },
{ Cube::RightPos, Cube::BottomEdge },
{ Cube::TopPos, Cube::BottomEdge },
{ Cube::BottomPos, Cube::BottomEdge }
},
// Back:
{
{ Cube::RightPos, Cube::BottomEdge },
{ Cube::LeftPos, Cube::BottomEdge },
{ Cube::TopPos, Cube::TopEdge },
{ Cube::BottomPos, Cube::BottomEdge }
}
};
Cube::Edge Cube::s_edgeTransformations[ Cube::NumEdges ][ Cube::NumEdges ] =
{
// current edge is LeftEdge:
{ Cube::TopEdge, // Left
Cube::BottomEdge, // Right
Cube::RightEdge, // Top
Cube::LeftEdge }, // Bottom
// Right:
{ Cube::BottomEdge,
Cube::TopEdge,
Cube::LeftEdge,
Cube::RightEdge },
// Top:
{ Cube::RightEdge,
Cube::LeftEdge,
Cube::BottomEdge,
Cube::TopEdge },
// Bottom:
{ Cube::LeftEdge,
Cube::RightEdge,
Cube::TopEdge,
Cube::BottomEdge }
};
Cube::Cube( QQuickItem* parent )
: QskStackBox( false, parent )
, m_destination( FrontPos )
, m_currentEdge( BottomEdge )
, m_isIntermediateHop( false )
{
// The code below covers the case where we need 2 cube movements to get
// to the desired position.
// We use transientIndexChanged here to be sure to start a new transition
// at the end; indexChanged doesn't work here.
connect( this, &QskStackBox::transientIndexChanged, this, [ this ]( qreal position )
{
const bool animationIsFinished = ( position == qFloor( position ) );
if( animationIsFinished && position != m_destination )
{
QTimer::singleShot( 0, this, [this]()
{
m_isIntermediateHop = true;
switchToPosition( m_destination );
} );
}
} );
QTimer::singleShot( 0, this, [this]()
{
Q_EMIT cubeIndexChanged( m_destination );
} );
}
void Cube::startAnimation( Qsk::Direction direction )
void Cube::doSwitch( Qsk::Direction direction, Position position )
{
using Animator = QskStackBoxAnimator4;
@ -27,12 +138,24 @@ void Cube::startAnimation( Qsk::Direction direction )
if ( animator == nullptr )
{
animator = new Animator( this );
animator->setEasingCurve( QEasingCurve::InOutQuad );
animator->setDuration( 1000 );
setAnimator( animator );
}
if( position == m_destination && !m_isIntermediateHop ) // 1 hop
{
animator->setEasingCurve( QEasingCurve::InOutQuad );
}
else if( !m_isIntermediateHop ) // 1st of 2 hops
{
animator->setEasingCurve( QEasingCurve::InQuad );
}
else // 2nd of 2 hops
{
animator->setEasingCurve( QEasingCurve::OutQuad );
m_isIntermediateHop = false;
}
const auto orientation = ( direction == Qsk::LeftToRight || direction == Qsk::RightToLeft )
? Qt::Horizontal : Qt::Vertical;
animator->setOrientation( orientation );
@ -40,32 +163,108 @@ void Cube::startAnimation( Qsk::Direction direction )
const bool inverted = ( direction == Qsk::LeftToRight || direction == Qsk::TopToBottom );
animator->setInverted( inverted );
int newIndex;
updateEdge( direction, position );
switch( direction )
setCurrentIndex( position );
if( position == m_destination )
{
case Qsk::LeftToRight:
case Qsk::TopToBottom:
newIndex = currentIndex() + 1;
break;
case Qsk::RightToLeft:
case Qsk::BottomToTop:
newIndex = currentIndex() - 1;
break;
Q_EMIT cubeIndexChanged( position );
}
}
void Cube::switchPosition( const Qsk::Direction direction )
{
m_destination = neighbor( currentPosition(), direction );
doSwitch( direction, m_destination );
}
void Cube::switchToPosition( const Position position )
{
if( currentPosition() == position )
return;
m_destination = position;
const auto direction = this->direction( currentPosition(), position );
const auto nextPosition = neighbor( currentPosition(), direction );
doSwitch( direction, nextPosition );
}
void Cube::keyPressEvent( QKeyEvent* event )
{
Qsk::Direction direction;
switch( event->key() )
{
case Qt::Key_Up:
direction = Qsk::TopToBottom;
break;
case Qt::Key_Down:
direction = Qsk::BottomToTop;
break;
case Qt::Key_Left:
direction = Qsk::LeftToRight;
break;
case Qt::Key_Right:
direction = Qsk::RightToLeft;
break;
default:
return;
}
newIndex %= itemCount();
if( newIndex < 0 )
newIndex += itemCount();
switchPosition( direction );
}
setCurrentIndex( newIndex );
Cube::Position Cube::currentPosition() const
{
return static_cast< Position >( currentIndex() );
}
Cube::Position Cube::neighbor( const Position position, const Qsk::Direction direction ) const
{
const auto index = s_edgeTransformations[ m_currentEdge ][ direction ];
const auto n = s_neighbors[ position ][ index ].first;
return n;
}
Qsk::Direction Cube::direction( const Position from, const Position to ) const
{
// if direct neighbor: use that direction
// otherwise: we need 2 swipes, direction doesn't matter, so choose right to left
const auto neighbors = s_neighbors[ from ];
for( int i = 0; i < NumEdges; ++i )
{
if( neighbors[ i ].first == to )
{
return static_cast< Qsk::Direction >( i );
}
}
return Qsk::RightToLeft;
}
void Cube::updateEdge( Qsk::Direction direction, Position position )
{
m_currentEdge = s_neighbors[ currentPosition() ][ direction ].second;
// When going back to Front, Left etc., switch back to
// the bottom edge, otherwise it gets to confusing:
if( position != TopPos && position != BottomPos )
{
m_currentEdge = BottomEdge;
}
}
MainItem::MainItem( QQuickItem* parent )
: QskControl( parent )
, m_cube( new Cube( this ) )
, m_mainLayout( new QskLinearBox( Qt::Horizontal, m_cube ) )
, m_otherLayout( new QskLinearBox( Qt::Horizontal, m_cube ) )
, m_mainLayout( new QskLinearBox( Qt::Horizontal, this ) )
, m_menuBar( new MenuBar( m_mainLayout ) )
, m_cube( new Cube( m_mainLayout ) )
{
setAutoLayoutChildren( true );
setAcceptedMouseButtons( Qt::LeftButton );
@ -77,18 +276,32 @@ MainItem::MainItem( QQuickItem* parent )
m_mainLayout->setSpacing( 0 );
m_otherLayout->setSpacing( 0 );
connect( m_menuBar, &MenuBar::pageChangeRequested, this, [this]( int index )
{
const auto position = static_cast< Cube::Position >( index );
m_cube->switchToPosition( position );
} );
(void) new MenuBar( m_mainLayout );
(void) new DashboardPage( m_mainLayout );
connect( m_cube, &Cube::cubeIndexChanged, m_menuBar, &MenuBar::setActivePage );
(void) new MenuBar( m_otherLayout );
(void) new RoomsPage( m_otherLayout );
auto* const dashboardPage = new DashboardPage( m_cube );
auto* const roomsPage = new RoomsPage( m_cube );
auto* const devicesPage = new DevicesPage( m_cube );
auto* const statisticsPage = new StatisticsPage( m_cube );
auto* const storagePage = new StoragePage( m_cube );
auto* const membersPage = new MembersPage( m_cube );
m_cube->addItem( m_mainLayout );
m_cube->addItem( m_otherLayout );
m_cube->insertItem( Cube::LeftPos, statisticsPage );
m_cube->insertItem( Cube::RightPos, roomsPage );
m_cube->insertItem( Cube::TopPos, storagePage );
m_cube->insertItem( Cube::BottomPos, membersPage );
m_cube->insertItem( Cube::FrontPos, dashboardPage );
m_cube->insertItem( Cube::BackPos, devicesPage );
m_cube->setCurrentItem( m_mainLayout );
// the current item needs to be the one at the Front:
m_cube->setCurrentItem( dashboardPage );
installEventFilter( this );
}
void MainItem::gestureEvent( QskGestureEvent* event )
@ -96,7 +309,7 @@ void MainItem::gestureEvent( QskGestureEvent* event )
if( event->gesture()->state() == QskGesture::Finished
&& event->gesture()->type() == QskGesture::Pan )
{
auto* panGesture = static_cast< const QskPanGesture* >( event->gesture().get() );
const auto* panGesture = static_cast< const QskPanGesture* >( event->gesture().get() );
const auto delta = panGesture->origin() - panGesture->position();
@ -111,7 +324,20 @@ void MainItem::gestureEvent( QskGestureEvent* event )
direction = ( delta.y() < 0 ) ? Qsk::TopToBottom : Qsk::BottomToTop;
}
m_cube->startAnimation( direction );
m_cube->switchPosition( direction );
}
}
bool MainItem::eventFilter( QObject* object, QEvent* event )
{
if ( event->type() == QEvent::KeyPress )
{
QCoreApplication::sendEvent( m_cube, event );
return true;
}
else
{
return QObject::eventFilter( object, event );
}
}
@ -136,3 +362,5 @@ bool MainItem::gestureFilter( QQuickItem* item, QEvent* event )
return recognizer.processEvent( item, event, false );
}
#include "moc_MainItem.cpp"

View File

@ -6,14 +6,61 @@
#include <QQuickWindow>
class MenuBar;
class QskBox;
class QskLinearBox;
class Cube : public QskStackBox
{
Q_OBJECT
public:
enum Edge {
LeftEdge = Qsk::LeftToRight,
RightEdge = Qsk::RightToLeft,
TopEdge = Qsk::TopToBottom,
BottomEdge = Qsk::BottomToTop,
NumEdges
};
Q_ENUM( Edge )
enum Position {
LeftPos = LeftEdge,
RightPos = RightEdge,
TopPos = TopEdge,
BottomPos = BottomEdge,
FrontPos,
BackPos,
NumPositions
};
Q_ENUM( Position )
explicit Cube( QQuickItem* parent = nullptr );
void startAnimation( Qsk::Direction direction );
public Q_SLOTS:
void switchPosition( const Qsk::Direction direction );
void switchToPosition( const Cube::Position position );
Q_SIGNALS:
// might be different from indexChanged:
void cubeIndexChanged( const int index );
protected:
void keyPressEvent( QKeyEvent* event ) override;
private:
Position currentPosition() const;
Position neighbor( const Position position, const Qsk::Direction direction ) const;
Qsk::Direction direction( const Position from, const Position to ) const;
void updateEdge( Qsk::Direction direction, Position position );
void doSwitch( Qsk::Direction direction, Position position );
Position m_destination;
Edge m_currentEdge;
bool m_isIntermediateHop;
static QPair< Position, Edge > s_neighbors[ NumPositions ][ NumEdges ];
static Edge s_edgeTransformations[ NumEdges ][ NumEdges ];
};
class MainItem : public QskControl
@ -24,12 +71,13 @@ class MainItem : public QskControl
MainItem( QQuickItem* parent = nullptr );
protected:
bool eventFilter(QObject *obj, QEvent *event) override final;
bool gestureFilter( QQuickItem*, QEvent* ) override final;
void gestureEvent( QskGestureEvent* ) override final;
private:
Cube* m_cube;
QskLinearBox* m_mainLayout;
QskLinearBox* m_otherLayout;
MenuBar* m_menuBar;
Cube* m_cube;
QskPanGestureRecognizer m_panRecognizer;
};

View File

@ -0,0 +1,21 @@
/******************************************************************************
* Copyright (C) 2021 Edelhirsch Software GmbH
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#include "MembersPage.h"
#include <QskSkin.h>
#include <QskTextLabel.h>
QSK_SUBCONTROL( MembersPage, Panel )
MembersPage::MembersPage( QQuickItem* parent )
: QskLinearBox( Qt::Vertical, parent )
{
auto* const textLabel = new QskTextLabel( "members page", this );
textLabel->setAlignmentHint( QskTextLabel::Text, Qt::AlignCenter );
textLabel->setFontRole( QskSkin::HugeFont );
}
#include "moc_MembersPage.cpp"

View File

@ -0,0 +1,19 @@
/******************************************************************************
* Copyright (C) 2021 Edelhirsch Software GmbH
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#pragma once
#include <QskGridBox.h>
#include <QskLinearBox.h>
class MembersPage : public QskLinearBox
{
Q_OBJECT
public:
QSK_SUBCONTROLS( Panel )
MembersPage( QQuickItem* parent );
};

View File

@ -5,58 +5,85 @@
#include "MenuBar.h"
#include <QTimer>
QSK_SUBCONTROL( MenuBarTopLabel, Graphic )
QSK_SUBCONTROL( MenuBarGraphicLabel, Graphic )
QSK_SUBCONTROL( MenuBarLabel, Text )
QSK_SUBCONTROL( MenuItem, Panel )
QSK_SUBCONTROL( MenuButton, Panel )
QSK_SUBCONTROL( MenuButton, Text )
QSK_SUBCONTROL( MenuButton, Graphic )
QSK_SUBCONTROL( MenuBar, Panel )
QSK_STATE( MenuItem, Active, ( QskAspect::FirstUserState << 1 ) )
MenuItem::MenuItem( const QString& name, QQuickItem* parent )
: QskLinearBox( Qt::Horizontal, parent )
MenuButton::MenuButton( const QString& name, QQuickItem* parent )
: QskPushButton( name, parent )
{
setCheckable( true );
initSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed );
setSpacing( 6 );
setAcceptHoverEvents( true );
setSubcontrolProxy( QskPushButton::Panel, MenuButton::Panel );
setSubcontrolProxy( QskPushButton::Text, MenuButton::Text );
setSubcontrolProxy( QskPushButton::Graphic, MenuButton::Graphic );
setPanel( true );
setSubcontrolProxy( QskBox::Panel, MenuItem::Panel );
auto graphicLabel = new MenuBarGraphicLabel( name, this );
graphicLabel->setSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed );
graphicLabel->setFixedWidth( metric( MenuBarGraphicLabel::Graphic | QskAspect::Size ) );
new MenuBarLabel( name, this );
setGraphicSource( name );
}
MenuBar::MenuBar( QQuickItem* parent )
: QskLinearBox( Qt::Vertical, parent )
, m_currentIndex( Cube::FrontPos )
{
setPanel( true );
setSubcontrolProxy( QskBox::Panel, MenuBar::Panel );
initSizePolicy( QskSizePolicy::Minimum, QskSizePolicy::Preferred );
setSpacing( 8 );
initSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Preferred );
setSpacing( 0 );
auto graphicLabel = new MenuBarTopLabel( "main-icon", this );
graphicLabel->setMargins( marginHint( MenuBarTopLabel::Graphic ) );
graphicLabel->setSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed );
m_entryStrings = { "Dashboard", "Rooms", "Devices", "Statistics", "Storage", "Members" };
for( const auto& entryString : qAsConst( m_entryStrings ) )
// ### unify the information with the one from MainItem
const QVector< QPair< Cube::Position, QString > > entries =
{
auto* entry = new MenuItem( entryString, this );
m_entries.append( entry );
}
{ Cube::FrontPos, "Dashboard" },
{ Cube::RightPos, "Rooms" },
{ Cube::BackPos, "Devices" },
{ Cube::LeftPos, "Statistics" },
{ Cube::TopPos, "Storage" },
{ Cube::BottomPos, "Members" },
};
m_entries.at( m_activeEntry )->setSkinStateFlag( MenuItem::Active );
for( const auto& entry : entries )
{
auto* button = new MenuButton( entry.second, this );
m_buttons[ entry.first ] = button;
connect( button, &QskPushButton::pressed, this, [ this, entry ]()
{
for( auto* button : qAsConst( m_buttons ) )
{
// the right button will be set to checked after this
button->setChecked( false );
}
Q_EMIT pageChangeRequested( entry.first );
} );
}
addSpacer( 0, 1 ); // fill the space at the bottom
new MenuItem( "Logout", this );
new MenuButton( "Logout", this );
}
void MenuBar::setActivePage( const int index )
{
m_buttons[ m_currentIndex ]->setChecked( false );
m_currentIndex = index;
QTimer::singleShot( 0, this, [this]()
{
m_buttons[ m_currentIndex ]->setChecked( true );
} );
}
#include "moc_MenuBar.cpp"

View File

@ -7,8 +7,11 @@
#include <QskGraphicLabel.h>
#include <QskLinearBox.h>
#include <QskPushButton.h>
#include <QskTextLabel.h>
#include "MainItem.h"
class MenuBarTopLabel final : public QskGraphicLabel
{
Q_OBJECT
@ -23,43 +26,14 @@ class MenuBarTopLabel final : public QskGraphicLabel
}
};
class MenuBarGraphicLabel final : public QskGraphicLabel
class MenuButton final : public QskPushButton
{
Q_OBJECT
public:
QSK_SUBCONTROLS( Graphic )
QSK_SUBCONTROLS( Panel, Text, Graphic )
MenuBarGraphicLabel( const QString& icon, QQuickItem* parent = nullptr )
: QskGraphicLabel( icon, parent )
{
setSubcontrolProxy( QskGraphicLabel::Graphic, Graphic );
}
};
class MenuBarLabel final : public QskTextLabel
{
Q_OBJECT
public:
QSK_SUBCONTROLS( Text )
MenuBarLabel( const QString& text, QQuickItem* parent = nullptr )
: QskTextLabel( text, parent )
{
setSubcontrolProxy( QskTextLabel::Text, Text );
}
};
class MenuItem final : public QskLinearBox
{
Q_OBJECT
public:
QSK_SUBCONTROLS( Panel )
QSK_STATES( Active )
MenuItem( const QString& name, QQuickItem* parent );
MenuButton( const QString& name, QQuickItem* parent );
};
class MenuBar final : public QskLinearBox
@ -71,8 +45,13 @@ class MenuBar final : public QskLinearBox
MenuBar( QQuickItem* parent );
Q_SIGNALS:
void pageChangeRequested( const int index );
public Q_SLOTS:
void setActivePage( const int index );
private:
QList< QString > m_entryStrings;
QList< MenuItem* > m_entries;
uint m_activeEntry = 0;
MenuButton* m_buttons[ Cube::NumPositions ];
uint m_currentIndex;
};

View File

@ -4,12 +4,12 @@
*****************************************************************************/
#include "MyDevices.h"
#include "Skin.h"
#include "RoundedIcon.h"
#include <QskGraphic.h>
#include <QskGraphicLabel.h>
#include <QskGridBox.h>
#include <QskSkin.h>
#include <QskTextLabel.h>
#include <QImage>
@ -26,8 +26,10 @@ namespace
auto icon = new RoundedIcon( isBright, this );
icon->setPale( true );
icon->setSource( name );
icon->setGraphicSource( name );
icon->setGraphicStrutSize( { 36, 36 } );
icon->setFixedSize( 68, 68 );
icon->setCheckable( true );
auto textLabel = new QskTextLabel( name, this );
textLabel->setFontRole( QskSkin::TinyFont );

View File

@ -1,36 +0,0 @@
/******************************************************************************
* Copyright (C) 2021 Edelhirsch Software GmbH
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#include "PieChart.h"
QSK_SUBCONTROL( PieChart, Panel )
QSK_SUBCONTROL( PieChart, Labels )
PieChart::PieChart( QQuickItem* parent )
: QskControl( parent )
{
}
QVector< float > PieChart::angles() const
{
return m_angles;
}
void PieChart::setAngles( const QVector< float >& angles )
{
m_angles = angles;
}
QVector< QString > PieChart::labels() const
{
return m_labels;
}
void PieChart::setLabels( const QVector< QString >& labels )
{
m_labels = labels;
}
#include "moc_PieChart.cpp"

View File

@ -1,28 +0,0 @@
/******************************************************************************
* Copyright (C) 2021 Edelhirsch Software GmbH
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#pragma once
#include <QskControl.h>
class PieChart : public QskControl
{
Q_OBJECT
public:
QSK_SUBCONTROLS( Panel, Labels )
PieChart( QQuickItem* parent = nullptr );
QVector< float > angles() const;
void setAngles( const QVector< float >& angles );
QVector< QString > labels() const;
void setLabels( const QVector< QString >& labels );
private:
QVector< float > m_angles;
QVector< QString > m_labels;
};

View File

@ -1,88 +0,0 @@
/******************************************************************************
* Copyright (C) 2021 Edelhirsch Software GmbH
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#include "PieChartSkinlet.h"
#include "PieChart.h"
#include <QskBoxNode.h>
#include <QskBoxShapeMetrics.h>
#include <QskBoxBorderMetrics.h>
#include <QskBoxBorderColors.h>
PieChartSkinlet::PieChartSkinlet( QskSkin* skin )
: QskSkinlet( skin )
{
setNodeRoles( { PanelRole, LabelsRole } );
}
QRectF PieChartSkinlet::subControlRect( const QskSkinnable*,
const QRectF& contentsRect, QskAspect::Subcontrol ) const
{
return contentsRect;
}
QSGNode* PieChartSkinlet::updateSubNode( const QskSkinnable* skinnable,
quint8 nodeRole, QSGNode* node ) const
{
const auto pieChart = static_cast< const PieChart* >( skinnable );
switch( nodeRole )
{
case PanelRole:
return updatePanelNode( pieChart, node );
case LabelsRole:
return updateLabelsNode( pieChart, node );
default:
return nullptr;
}
}
QSGNode* PieChartSkinlet::updatePanelNode( const PieChart* pieChart, QSGNode* node ) const
{
auto boxNode = static_cast< QskBoxNode* >( node );
if( boxNode == nullptr )
{
boxNode = new QskBoxNode;
}
auto panelRect = subControlRect( pieChart, pieChart->contentsRect(), PieChart::Panel );
// ### when displaying a legend we might want to revise this
if( panelRect.width() > panelRect.height() )
{
panelRect.setWidth( panelRect.height() );
}
else if( panelRect.width() < panelRect.height() )
{
panelRect.setHeight( panelRect.width() );
}
const qreal radius = panelRect.width() / 2;
QskBoxShapeMetrics shapeMetrics( radius, radius, radius, radius );
QskBoxBorderMetrics borderMetrics = pieChart->boxBorderMetricsHint( PieChart::Panel );
QskBoxBorderColors borderColors = pieChart->boxBorderColorsHint( PieChart::Panel );
QskGradient gradient = pieChart->gradientHint( PieChart::Panel );
boxNode->setBoxData( panelRect, shapeMetrics, borderMetrics, borderColors, gradient );
return boxNode;
}
QSGNode* PieChartSkinlet::updateLabelsNode( const PieChart* pieChart, QSGNode* ) const
{
const int labelsCount = pieChart->labels().count();
if( labelsCount < 1 )
{
return nullptr;
}
return nullptr;
}
#include "moc_PieChartSkinlet.cpp"

View File

@ -1,35 +0,0 @@
/******************************************************************************
* Copyright (C) 2021 Edelhirsch Software GmbH
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#pragma once
#include <QskSkinlet.h>
class PieChart;
class PieChartSkinlet : public QskSkinlet
{
Q_GADGET
public:
enum NodeRole
{
PanelRole,
LabelsRole
};
Q_INVOKABLE PieChartSkinlet( QskSkin* skin = nullptr );
QRectF subControlRect( const QskSkinnable*,
const QRectF&, QskAspect::Subcontrol ) const override;
protected:
virtual QSGNode* updateSubNode( const QskSkinnable*,
quint8 nodeRole, QSGNode* node ) const override;
private:
QSGNode* updatePanelNode( const PieChart*, QSGNode* ) const;
QSGNode* updateLabelsNode( const PieChart*, QSGNode* ) const;
};

View File

@ -7,7 +7,7 @@
#include <QskPushButton.h>
class RoundButton : QskPushButton
class RoundButton : public QskPushButton
{
Q_OBJECT

View File

@ -7,25 +7,24 @@
QSK_SUBCONTROL( RoundedIcon, Panel )
QSK_SUBCONTROL( RoundedIcon, PalePanel )
QSK_SUBCONTROL( RoundedIcon, Graphic )
QSK_STATE( RoundedIcon, Bright, ( QskAspect::FirstUserState << 1 ) )
RoundedIcon::RoundedIcon( bool isBright, QQuickItem* parent )
: QskGraphicLabel( parent )
: QskPushButton( parent )
{
setAlignment( Qt::AlignCenter );
setFillMode( QskGraphicLabel::Pad );
if( isBright )
setSkinStateFlag( Bright );
setPanel( true );
setPale( false );
setSubcontrolProxy( QskPushButton::Graphic, Graphic );
}
void RoundedIcon::setPale( bool on )
{
setSubcontrolProxy( QskGraphicLabel::Panel, on ? PalePanel : Panel );
setSubcontrolProxy( QskPushButton::Panel, on ? PalePanel : Panel );
}
#include "moc_RoundedIcon.cpp"

View File

@ -5,18 +5,21 @@
#pragma once
#include <QskGraphicLabel.h>
#include <QskPushButton.h>
class QskGraphicLabel;
class RoundedIcon : public QskGraphicLabel
class RoundedIcon : public QskPushButton
{
Q_OBJECT
public:
QSK_SUBCONTROLS( Panel, PalePanel )
QSK_SUBCONTROLS( Panel, PalePanel, Graphic )
QSK_STATES( Bright ) // to differentiate between orange and purple
enum {
NormalRole,
CheckedRole,
} GraphicRole;
RoundedIcon( bool isBright, QQuickItem* parent = nullptr );
void setPale( bool );

View File

@ -9,26 +9,34 @@
#include "BoxWithButtons.h"
#include "CircularProgressBar.h"
#include "CircularProgressBarSkinlet.h"
#include "DashboardPage.h"
#include "Diagram.h"
#include "DiagramSkinlet.h"
#include "GridBox.h"
#include "LightDisplay.h"
#include "LightDisplaySkinlet.h"
#include "DashboardPage.h"
#include "MenuBar.h"
#include "RoundedIcon.h"
#include "RoomsPage.h"
#include "RoundButton.h"
#include "RoundedIcon.h"
#include "StorageBar.h"
#include "StorageBarSkinlet.h"
#include "StorageMeter.h"
#include "StoragePage.h"
#include "TopBar.h"
#include "UsageBox.h"
#include "UsageDiagram.h"
#include <QskArcMetrics.h>
#include <QskBoxShapeMetrics.h>
#include <QskBoxBorderMetrics.h>
#include <QskBoxBorderColors.h>
#include <QskBoxBorderMetrics.h>
#include <QskBoxShapeMetrics.h>
#include <QskColorFilter.h>
#include <QskFunctions.h>
#include <QskProgressBar.h>
#include <QskShadowMetrics.h>
#include <QskSkinHintTableEditor.h>
#include <QskStateCombination.h>
#include <QskTextLabel.h>
#include <QFontDatabase>
@ -39,7 +47,7 @@ namespace
{
QFont font( "Proxima Nova" );
if( semiBold )
if ( semiBold )
{
font.setWeight( QFont::Bold );
}
@ -47,7 +55,6 @@ namespace
font.setPointSizeF( pointSize /*/ qskDpiScaled( 1.0 )*/ );
return font;
}
}
Skin::Skin( const Palette& palette, QObject* parent )
@ -56,6 +63,7 @@ Skin::Skin( const Palette& palette, QObject* parent )
declareSkinlet< CircularProgressBar, CircularProgressBarSkinlet >();
declareSkinlet< Diagram, DiagramSkinlet >();
declareSkinlet< LightDisplay, LightDisplaySkinlet >();
declareSkinlet< StorageBar, StorageBarSkinlet >();
initHints( palette );
}
@ -80,42 +88,43 @@ void Skin::initHints( const Palette& palette )
QskSkinHintTableEditor ed( &hintTable() );
ed.setPadding( MainContentGridBox::Panel, {19, 0, 27, 24} );
ed.setPadding( MainContentGridBox::Panel, { 19, 0, 27, 24 } );
// menu bar:
ed.setMargin( MenuBarTopLabel::Graphic, { 50, 5, 50, 65 } );
ed.setPadding( MenuBar::Panel, {0, 35, 0, 12} );
ed.setStrutSize( MenuItem::Panel | QskAspect::Size, {140, 40} );
ed.setPadding( MenuItem::Panel, {30, 0, 30, 0} );
ed.setStrutSize( MenuButton::Panel | QskAspect::Size, {140, 40} );
QColor color( Qt::white );
color.setAlphaF( 0.09 );
ed.setGradient( MenuItem::Panel | QskControl::Hovered, color );
ed.setGradient( MenuButton::Panel | QskControl::Hovered, color );
color.setAlphaF( 0.14 );
ed.setGradient( MenuItem::Panel | MenuItem::Active, color );
ed.setGradient( MenuButton::Panel | MenuButton::Checked, color );
ed.setSpacing( MenuButton::Panel, 10 );
ed.setColor( MenuBarLabel::Text, Qt::white );
ed.setFontRole( MenuBarLabel::Text, QskSkin::SmallFont );
ed.setColor( MenuButton::Text, Qt::white );
ed.setFontRole( MenuButton::Text, QskSkin::SmallFont );
ed.setAlignment( MenuButton::Text, Qt::AlignLeft | Qt::AlignVCenter );
ed.setMargin( MenuBarTopLabel::Graphic, { 50, 0, 50, 54 } );
ed.setMetric( MenuBarGraphicLabel::Graphic | QskAspect::Size, 14 );
ed.setAlignment( MenuBarGraphicLabel::Graphic, Qt::AlignCenter );
ed.setPadding( MenuButton::Graphic, { 30, 0, 0, 0 } );
ed.setStrutSize( MenuButton::Graphic, { 14, -1 } );
ed.setAlignment( MenuButton::Graphic, Qt::AlignCenter );
// top bar:
ed.setPadding( TopBar::Panel, {25, 35, 25, 0} );
ed.setPadding( TopBar::Panel, { 25, 35, 25, 0 } );
ed.setColor( TopBarItem::Item1 | QskAspect::TextColor, "#ff3122" );
ed.setColor( TopBarItem::Item2 | QskAspect::TextColor, "#6776ff" );
ed.setColor( TopBarItem::Item3 | QskAspect::TextColor, "#f99055" );
ed.setColor( TopBarItem::Item4 | QskAspect::TextColor, "#6776ff" );
ed.setColor( TopBarItem::Item1 | QskAspect::TextColor, 0xffff3122 );
ed.setColor( TopBarItem::Item2 | QskAspect::TextColor, 0xff6776ff );
ed.setColor( TopBarItem::Item3 | QskAspect::TextColor, 0xfff99055 );
ed.setColor( TopBarItem::Item4 | QskAspect::TextColor, 0xff6776ff );
// conical gradients are counterclockwise, so specify the 2nd color first:
ed.setGradient( TopBarItem::Item1, { QskGradient::Horizontal, "#FF3122", "#FF5C00" } );
ed.setGradient( TopBarItem::Item2, { QskGradient::Horizontal, "#6100FF", "#6776FF" } );
ed.setGradient( TopBarItem::Item3, { QskGradient::Horizontal, "#FF3122", "#FFCE50" } );
ed.setGradient( TopBarItem::Item4, { QskGradient::Horizontal, "#6100FF", "#6776FF" } );
// arcs are counterclockwise, so specify the 2nd color first:
ed.setGradient( TopBarItem::Item1, 0xffff3122, 0xffff5c00 );
ed.setGradient( TopBarItem::Item2, 0xff6100ff, 0xff6776ff );
ed.setGradient( TopBarItem::Item3, 0xffff3122, 0xffffce50 );
ed.setGradient( TopBarItem::Item4, 0xff6100ff, 0xff6776ff );
// the bar gradient is defined through the top bar items above
ed.setArcMetrics( CircularProgressBar::Groove, { 8.53, 90, -360 } );
@ -126,14 +135,14 @@ void Skin::initHints( const Palette& palette )
ed.setFontRole( TimeTitleLabel::Text, Skin::TitleFont );
ed.setFontRole( TimeLabel::Text, QskSkin::HugeFont );
ed.setColor( TimeLabel::Text, "#6776FF" );
ed.setColor( TimeLabel::Text, 0xff6776ff );
// boxes:
ed.setPadding( Box::Panel, 8 );
// content in boxes (indoor temperature, humidity etc.):
ed.setFontRole( UsageBox::Separator, QskSkin::SmallFont );
ed.setColor( UsageBox::Separator, "#dddddd" );
ed.setColor( UsageBox::Separator, 0xffdddddd );
ed.setPadding( BoxWithButtons::Panel, 8 );
@ -141,14 +150,41 @@ void Skin::initHints( const Palette& palette )
{
ed.setBoxShape( subControl, 6 );
QskGradient normal( QskGradient::Vertical, "#6776FF", "#6100FF" );
QskGradient bright( QskGradient::Vertical, "#ff7d34", "#ff3122" );
QskGradient normal( 0xff6776ff, 0xff6100ff );
normal.setLinearDirection( Qt::Vertical );
if ( subControl == RoundedIcon::PalePanel )
QskGradient bright( 0xffff7d34, 0xffff3122 );
bright.setLinearDirection( Qt::Vertical );
if ( subControl == RoundedIcon::PalePanel ) // My Devices section
{
const uint alpha = 38;
normal.setAlpha( alpha );
bright.setAlpha( alpha );
auto pressedNormal = normal;
pressedNormal.setAlpha( 10 );
auto pressedBright = bright;
pressedBright.setAlpha( 10 );
const int duration = 300;
ed.setGradient( RoundedIcon::PalePanel | QskAbstractButton::Checked, pressedNormal );
ed.setGradient(
RoundedIcon::PalePanel | RoundedIcon::Bright | QskAbstractButton::Checked,
pressedBright );
ed.setAnimation( RoundedIcon::PalePanel | QskAspect::Color, duration );
ed.setGraphicRole( RoundedIcon::Graphic, RoundedIcon::NormalRole );
ed.setGraphicRole( RoundedIcon::Graphic | QskAbstractButton::Checked,
RoundedIcon::CheckedRole,
{ QskStateCombination::CombinationNoState, RoundedIcon::Bright } );
ed.setAnimation( RoundedIcon::Graphic, duration );
QskColorFilter filter;
filter.addColorSubstitution(
0xff606675, palette.deviceGraphic ); // color comes from the SVG
setGraphicFilter( RoundedIcon::CheckedRole, filter );
}
ed.setGradient( subControl, normal );
@ -156,7 +192,7 @@ void Skin::initHints( const Palette& palette )
}
ed.setFontRole( BoxWithButtons::ValueText, QskSkin::HugeFont );
ed.setColor( BoxWithButtons::ValueText, "#929cb2" );
ed.setColor( BoxWithButtons::ValueText, 0xff929cb2 );
ed.setPadding( BoxWithButtons::ValuePanel, 0, 10, 0, 0 );
@ -170,16 +206,16 @@ void Skin::initHints( const Palette& palette )
ed.setStrutSize( UsageDiagramLegend::Symbol, 8, 8 );
ed.setBoxShape( UsageDiagramLegend::Symbol, 100, Qt::RelativeSize ); // a circle
ed.setGradient( UsageDiagramLegend::Symbol | UsageDiagramLegend::Water, {"#6776ff"} );
ed.setGradient( UsageDiagramLegend::Symbol | UsageDiagramLegend::Electricity, {"#ff3122"} );
ed.setGradient( UsageDiagramLegend::Symbol | UsageDiagramLegend::Gas, {"#ff7d34"} );
ed.setGradient( UsageDiagramLegend::Symbol | UsageDiagramLegend::Water, { 0xff6776ff } );
ed.setGradient( UsageDiagramLegend::Symbol | UsageDiagramLegend::Electricity, { 0xffff3122 } );
ed.setGradient( UsageDiagramLegend::Symbol | UsageDiagramLegend::Gas, { 0xffff7d34 } );
ed.setPadding( UsageDiagramBox::Panel, 0 );
// new diagram:
ed.setColor( Diagram::ChartArea1, "#666776ff" );
ed.setColor( Diagram::ChartArea2, "#66ff3122" );
ed.setColor( Diagram::ChartArea3, "#66ff7d34" );
ed.setColor( Diagram::ChartArea1, 0x666776ff );
ed.setColor( Diagram::ChartArea2, 0x66ff3122 );
ed.setColor( Diagram::ChartArea3, 0x66ff7d34 );
ed.setColor( Diagram::ChartBar1, 0xff6776ff );
ed.setColor( Diagram::ChartBar2, 0xffff3122 );
@ -197,30 +233,25 @@ void Skin::initHints( const Palette& palette )
ed.setBoxShape( LightDisplay::Panel, 100, Qt::RelativeSize );
ed.setArcMetrics( LightDisplay::ColdAndWarmArc, 8.785, 0, 180 );
QskGradient coldGradient( Qt::Horizontal, { { 0.0, 0xffff3122 },
{ 0.2, 0xfffeeeb7 },
{ 0.3, 0xffa7b0ff },
{ 0.5, 0xff6776ff },
{ 1.0, Qt::black } } );
ed.setGradient( LightDisplay::ColdAndWarmArc, coldGradient );
ed.setMetric( LightDisplay::Tickmarks, 1 );
ed.setArcMetrics( LightDisplay::Tickmarks, { 4.69, 0, 180 } );
ed.setColor( LightDisplay::Tickmarks, 0x55929CB2 );
ed.setColor( LightDisplay::Tickmarks, 0x55929cb2 );
ed.setFontRole( LightDisplay::ValueText, QskSkin::LargeFont );
ed.setColor( LightDisplay::ValueText, "#929cb2" );
ed.setColor( LightDisplay::ValueText, 0xff929cb2 );
ed.setStrutSize( LightDisplay::Knob, { 20, 20 } );
ed.setBoxBorderMetrics( LightDisplay::Knob, 1 );
ed.setBoxBorderColors( LightDisplay::Knob, 0xffc4c4c4 );
ed.setBoxShape( LightDisplay::Knob, 100, Qt::RelativeSize );
// palette dependent skin hints:
ed.setGradient( MenuBar::Panel, palette.menuBar );
ed.setGradient( DashboardPage::Panel, palette.mainContent );
ed.setGradient( RoomsPage::Panel, palette.mainContent );
ed.setGradient( StoragePage::Panel, palette.mainContent );
ed.setColor( Box::Panel, palette.box.startColor() );
ed.setColor( Box::Panel, palette.box );
QskShadowMetrics shadowMetrics( 0, 10 );
ed.setShadowMetrics( Box::Panel, shadowMetrics );
ed.setShadowColor( Box::Panel, palette.shadow );
@ -235,9 +266,80 @@ void Skin::initHints( const Palette& palette )
ed.setGradient( LightDisplay::Panel, palette.box );
ed.setGradient( LightDisplay::Knob, palette.box );
ed.setGradient( LightDisplay::ColdAndWarmArc, palette.lightDisplayColdAndWarmArc );
ed.setBoxBorderColors( LightDisplay::Knob, palette.lightDisplayKnobBorder );
ed.setShadowMetrics( LightDisplay::Groove, { 0, 20 } );
ed.setShadowColor( LightDisplay::Groove, palette.shadow );
ed.setGradient( LightDisplay::Groove, palette.box );
ed.setBoxShape( LightDisplay::Groove, 100, Qt::RelativeSize );
ed.setGradient( RoundButton::Panel, palette.roundButton );
ed.setGradient( RoundButton::Panel | QskAbstractButton::Pressed, palette.roundButtonPressed,
{ QskStateCombination::CombinationNoState, RoundButton::Top } );
ed.setAnimation( RoundButton::Panel | QskAspect::Color, 100 );
ed.setBoxBorderColors( UsageDiagramBox::DaysBox, palette.weekdayBox );
ed.setColor( QskTextLabel::Text, palette.text );
ed.setColor( UsageDiagramBox::DayText, palette.text );
ed.setGradient( CircularProgressBar::Groove, palette.circularProgressBarGroove );
auto grooveGradient = palette.circularProgressBarGroove;
grooveGradient.setDirection( QskGradient::Linear );
ed.setGradient( CircularProgressBar::Groove, grooveGradient );
// storage bar
{
const auto make_gradient = []( const QColor color ) -> QskGradient {
return { color.lighter(), color };
};
ed.setGradient( StorageBar::Pictures, make_gradient( "#FFBE0B" ) );
ed.setGradient( StorageBar::Music, make_gradient( "#FB5607" ) );
ed.setGradient( StorageBar::Videos, make_gradient( "#FF006E" ) );
ed.setGradient( StorageBar::Documents, make_gradient( "#8338EC" ) );
ed.setGradient( StorageBar::Others, make_gradient( "#3A86FF" ) );
ed.setGradient( StorageBar::Free, make_gradient( "lightgray" ) );
}
// storage meter
{
ed.setGradient( StorageMeter::Status,
{ { { 0.00, "#00ff00" }, { 0.33, "#00ff00" }, { 0.33, "#ffaf00" }, { 0.66, "#ffaf00" },
{ 0.66, "#ff0000" }, { 1.00, "#ff0000" } } } );
}
}
Skin::Palette DaytimeSkin::palette() const
{
return {
0xff6d7bfb,
0xfffbfbfb,
Qt::white,
0xfff7f7f7,
0xffe5e5e5,
0xfff4f4f4,
Qt::black,
0xffe5e5e5,
0xffc4c4c4,
{ { { 0.0, 0xffff3122 }, { 0.2, 0xfffeeeb7 }, { 0.3, 0xffa7b0ff }, { 0.5, 0xff6776ff },
{ 1.0, Qt::black } } },
{ { { 0.0, 0xffc4c4c4 }, { 0.5, 0xfff8f8f8 }, { 1.0, 0xffc4c4c4 } } },
0xffdddddd,
};
}
Skin::Palette NighttimeSkin::palette() const
{
return {
0xff2937A7,
0xff040404,
Qt::black,
0xff0a0a0a,
0xff1a1a1a,
0xff0c0c0c,
Qt::white,
0xff4a4a4a,
0xff555555,
{ { { 0.0, 0xff991100 }, { 0.2, 0xff9a7a57 }, { 0.5, 0xff3726af }, { 1.0, Qt::black } } },
{ { { 0.0, 0xff666666 }, { 0.5, 0xff222222 }, { 1.0, 0xff333333 } } },
0xff222222,
};
}

View File

@ -11,34 +11,20 @@
class Skin : public QskSkin
{
public:
class Palette
struct Palette
{
public:
Palette( const QskGradient& menuBar, const QskGradient& mainContent,
const QskGradient& box, const QColor& lightDisplay,
const QskGradient& roundButton, const QColor& weekdayBox,
const QColor& text, const QColor& shadow,
const QskGradient& circularProgressBarGroove )
: menuBar( menuBar )
, mainContent( mainContent )
, box( box )
, lightDisplay( lightDisplay )
, roundButton( roundButton )
, weekdayBox( weekdayBox )
, text( text )
, shadow( shadow )
, circularProgressBarGroove( circularProgressBarGroove )
{
}
QskGradient menuBar;
QskGradient mainContent;
QskGradient box;
QColor lightDisplay;
QskGradient roundButton;
QColor menuBar;
QColor mainContent;
QColor box;
QColor roundButton;
QColor roundButtonPressed;
QColor weekdayBox;
QColor text;
QColor shadow;
QColor lightDisplayKnobBorder;
QskGradient lightDisplayColdAndWarmArc;
QskGradient circularProgressBarGroove;
QRgb deviceGraphic;
};
Skin( const Palette& palette, QObject* parent = nullptr );
@ -57,24 +43,22 @@ class DaytimeSkin : public Skin
{
public:
DaytimeSkin( QObject* parent = nullptr )
: Skin(
Skin::Palette( {"#6D7BFB"}, {"#fbfbfb"}, {"#ffffff"},
"#ffffff", {"#f7f7f7"}, {"#f4f4f4"}, Qt::black, 0xffe5e5e5,
{ QskGradient::Vertical, { { 0.0, 0xffc4c4c4 }, { 0.5, 0xfff8f8f8 }, { 1.0, 0xffc4c4c4 } } } )
, parent )
: Skin( palette(), parent )
{
}
private:
Palette palette() const;
};
class NighttimeSkin : public Skin
{
public:
NighttimeSkin( QObject* parent = nullptr )
: Skin(
Skin::Palette( {"#2937A7"}, {"#040404"}, {"#000000"},
"#000000", {"#0a0a0a"}, {"#0c0c0c"}, Qt::white, 0xff1a1a1a,
{ QskGradient::Vertical, { { 0.0, 0xff666666 }, { 0.5, 0xff222222 }, { 1.0, 0xff333333 } } } )
, parent )
: Skin( palette(), parent )
{
}
private:
Palette palette() const;
};

View File

@ -0,0 +1,21 @@
/******************************************************************************
* Copyright (C) 2021 Edelhirsch Software GmbH
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#include "StatisticsPage.h"
#include <QskSkin.h>
#include <QskTextLabel.h>
QSK_SUBCONTROL( StatisticsPage, Panel )
StatisticsPage::StatisticsPage( QQuickItem* parent )
: QskLinearBox( Qt::Vertical, parent )
{
auto* const textLabel = new QskTextLabel( "statistics page", this );
textLabel->setAlignmentHint( QskTextLabel::Text, Qt::AlignCenter );
textLabel->setFontRole( QskSkin::HugeFont );
}
#include "moc_StatisticsPage.cpp"

View File

@ -0,0 +1,19 @@
/******************************************************************************
* Copyright (C) 2021 Edelhirsch Software GmbH
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#pragma once
#include <QskGridBox.h>
#include <QskLinearBox.h>
class StatisticsPage : public QskLinearBox
{
Q_OBJECT
public:
QSK_SUBCONTROLS( Panel )
StatisticsPage( QQuickItem* parent );
};

View File

@ -0,0 +1,120 @@
/******************************************************************************
* Copyright (C) 2022 Edelhirsch Software GmbH
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#include "StorageBar.h"
#include <QskAnimator.h>
#include <QskBox.h>
#include <QskBoxShapeMetrics.h>
#include <QskSkinlet.h>
QSK_SUBCONTROL( StorageBar, Pictures )
QSK_SUBCONTROL( StorageBar, Music )
QSK_SUBCONTROL( StorageBar, Videos )
QSK_SUBCONTROL( StorageBar, Documents )
QSK_SUBCONTROL( StorageBar, Others )
QSK_SUBCONTROL( StorageBar, Free )
using S = StorageBar;
StorageBar::StorageBar( QskQuickItem* const parent )
: Inherited( parent )
{
static constexpr qreal size = 16.0;
static constexpr qreal radius = size / 2.0;
setMinimumSize( -1, size );
setMaximumSize( -1, size );
setBoxShapeHint( S::Pictures, { radius, 0.0, radius, 0.0 } );
setBoxShapeHint( S::Free, { 0.0, radius, 0.0, radius } );
}
qreal StorageBar::pictures() const
{
return m_pictures;
}
void StorageBar::setPictures( qreal newPictures )
{
if ( qFuzzyCompare( m_pictures, newPictures ) )
{
return;
}
m_pictures = newPictures;
Q_EMIT picturesChanged( m_pictures );
update();
}
qreal StorageBar::music() const
{
return m_music;
}
void StorageBar::setMusic( qreal newMusic )
{
if ( qFuzzyCompare( m_music, newMusic ) )
{
return;
}
m_music = newMusic;
Q_EMIT musicChanged( m_music );
update();
}
qreal StorageBar::videos() const
{
return m_videos;
}
void StorageBar::setVideos( qreal newVideos )
{
if ( qFuzzyCompare( m_videos, newVideos ) )
{
return;
}
m_videos = newVideos;
Q_EMIT videosChanged( m_videos );
update();
}
qreal StorageBar::documents() const
{
return m_documents;
}
void StorageBar::setDocuments( qreal newDocuments )
{
if ( qFuzzyCompare( m_documents, newDocuments ) )
{
return;
}
m_documents = newDocuments;
Q_EMIT documentsChanged( m_documents );
update();
}
qreal StorageBar::others() const
{
return m_others;
}
void StorageBar::setOthers( qreal newOthers )
{
if ( qFuzzyCompare( m_others, newOthers ) )
{
return;
}
m_others = newOthers;
Q_EMIT othersChanged( m_others );
update();
}
qreal StorageBar::free() const
{
return 1.0 - m_pictures - m_music - m_videos - m_documents - m_others;
}
#include "moc_StorageBar.cpp"

View File

@ -0,0 +1,51 @@
/******************************************************************************
* Copyright (C) 2022 Edelhirsch Software GmbH
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#pragma once
#include <QskControl.h>
class StorageBar final : public QskControl
{
using Inherited = QskControl;
Q_OBJECT
Q_PROPERTY( qreal pictures READ pictures WRITE setPictures NOTIFY picturesChanged )
Q_PROPERTY( qreal music READ music WRITE setMusic NOTIFY musicChanged )
Q_PROPERTY( qreal videos READ videos WRITE setVideos NOTIFY videosChanged )
Q_PROPERTY( qreal documents READ documents WRITE setDocuments NOTIFY documentsChanged )
Q_PROPERTY( qreal others READ others WRITE setOthers NOTIFY othersChanged )
public:
QSK_SUBCONTROLS( Pictures, Music, Videos, Documents, Others, Free )
explicit StorageBar( QskQuickItem* parent = nullptr );
qreal pictures() const;
void setPictures( qreal newPictures );
qreal music() const;
void setMusic( qreal newMusic );
qreal videos() const;
void setVideos( qreal newVideos );
qreal documents() const;
void setDocuments( qreal newDocuments );
qreal others() const;
void setOthers( qreal newOthers );
qreal free() const;
Q_SIGNALS:
void picturesChanged( qreal value );
void musicChanged( qreal value );
void videosChanged( qreal value );
void documentsChanged( qreal value );
void othersChanged( qreal value );
private:
qreal m_pictures{ 0.0 };
qreal m_music{ 0.0 };
qreal m_videos{ 0.0 };
qreal m_documents{ 0.0 };
qreal m_others{ 0.0 };
};

View File

@ -0,0 +1,107 @@
/******************************************************************************
* Copyright (C) 2022 Edelhirsch Software GmbH
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#include "StorageBarSkinlet.h"
#include "StorageBar.h"
using S = StorageBar;
StorageBarSkinlet::StorageBarSkinlet( QskSkin* skin )
: Inherited( skin )
{
setNodeRoles( { Pictures, Music, Videos, Documents, Others, Free } );
}
QRectF StorageBarSkinlet::subControlRect( const QskSkinnable* skinnable, const QRectF& contentsRect,
QskAspect::Subcontrol subControl ) const
{
const auto* const bar = static_cast< const S* >( skinnable );
auto x = contentsRect.x();
const auto y = contentsRect.y();
const auto w = contentsRect.width();
const auto h = contentsRect.height();
// segement widths
const auto p = w * bar->pictures();
const auto m = w * bar->music();
const auto v = w * bar->videos();
const auto d = w * bar->documents();
const auto o = w * bar->others();
const auto f = w * bar->free();
if ( subControl == S::Pictures )
{
return { x, y, p, h };
}
x += p;
if ( subControl == S::Music )
{
return { x, y, m, h };
}
x += m;
if ( subControl == S::Videos )
{
return { x, y, v, h };
}
x += v;
if ( subControl == S::Documents )
{
return { x, y, d, h };
}
x += d;
if ( subControl == S::Others )
{
return { x, y, o, h };
}
x += o;
if ( subControl == S::Free )
{
return { x, y, f, h };
}
return Inherited::subControlRect( skinnable, contentsRect, subControl );
}
namespace
{
inline QSGNode* updateSegmentBoxNode(
const S* const skinnable, const QskAspect::Subcontrol& subcontrol, QSGNode* const node )
{
return QskSkinlet::updateBoxNode( skinnable, node, skinnable->subControlRect( subcontrol ),
skinnable->gradientHint( subcontrol ), subcontrol );
}
}
QSGNode* StorageBarSkinlet::updateSubNode(
const QskSkinnable* const skinnable, const quint8 nodeRole, QSGNode* const node ) const
{
const auto* const bar = static_cast< const S* >( skinnable );
switch ( nodeRole )
{
case Pictures:
return updateSegmentBoxNode( bar, S::Pictures, node );
case Music:
return updateSegmentBoxNode( bar, S::Music, node );
case Videos:
return updateSegmentBoxNode( bar, S::Videos, node );
case Documents:
return updateSegmentBoxNode( bar, S::Documents, node );
case Others:
return updateSegmentBoxNode( bar, S::Others, node );
case Free:
return updateSegmentBoxNode( bar, S::Free, node );
default:
return Inherited::updateSubNode( skinnable, nodeRole, node );
}
}
#include "moc_StorageBarSkinlet.cpp"

View File

@ -0,0 +1,32 @@
/******************************************************************************
* Copyright (C) 2022 Edelhirsch Software GmbH
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#pragma once
#include <QskSkinlet.h>
class StorageBarSkinlet final : public QskSkinlet
{
Q_GADGET
using Inherited = QskSkinlet;
public:
enum NodeRole
{
Pictures,
Music,
Videos,
Documents,
Others,
Free
};
Q_INVOKABLE StorageBarSkinlet( QskSkin* skin = nullptr );
private:
QRectF subControlRect( const QskSkinnable* skinnable, const QRectF& contentsRect,
QskAspect::Subcontrol subControl ) const override;
QSGNode* updateSubNode(
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const override;
};

View File

@ -0,0 +1,65 @@
/******************************************************************************
* Copyright (C) 2022 Edelhirsch Software GmbH
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#include "StorageMeter.h"
#include "CircularProgressBar.h"
#include <QskSkin.h>
#include <QskTextLabel.h>
QSK_SUBCONTROL( StorageMeter, Status )
namespace
{
inline QString make_text( const QLocale& locale, const qreal value )
{
return locale.toString( static_cast< int >( value ) ) + " " + locale.percent();
}
}
StorageMeter::StorageMeter( QQuickItem* parent ) noexcept
: CircularProgressBar( parent )
, label( new QskTextLabel( this ) )
{
setAutoLayoutChildren( true );
setSizePolicy( QskSizePolicy::Preferred, QskSizePolicy::Constrained );
label->setText( make_text( locale(), value() ) );
label->setSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed );
label->setLayoutAlignmentHint( Qt::AlignCenter );
label->setFontRole( QskSkin::SmallFont );
}
void StorageMeter::setValue( const qreal value )
{
const auto gradient = gradientHint( StorageMeter::Status );
const auto color = gradient.extracted( value / 100.0, value / 100.0 ).startColor();
setGradientHint( StorageMeter::Bar, { color, color.lighter() } );
CircularProgressBar::setValue( value );
label->setTextColor( color );
label->setText( make_text( locale(), value ) );
}
QSizeF StorageMeter::contentsSizeHint( Qt::SizeHint which, const QSizeF& constraint ) const
{
if ( which != Qt::PreferredSize )
return QSizeF();
qreal size;
if ( constraint.width() > 0 )
{
size = constraint.width();
}
else if ( constraint.height() > 0 )
{
size = constraint.height();
}
else
{
size = 57;
}
return QSizeF( size, size );
}

View File

@ -0,0 +1,22 @@
/******************************************************************************
* Copyright (C) 2022 Edelhirsch Software GmbH
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#pragma once
#include "CircularProgressBar.h"
#include <QskControl.h>
class StorageMeter final : public CircularProgressBar
{
public:
QSK_SUBCONTROLS( Status )
explicit StorageMeter( QQuickItem* parent = nullptr ) noexcept;
public Q_SLOTS:
void setValue( qreal value );
private:
QSizeF contentsSizeHint( Qt::SizeHint which, const QSizeF& constraint ) const override;
class QskTextLabel* label = nullptr;
};

View File

@ -0,0 +1,144 @@
/******************************************************************************
* Copyright (C) 2022 Edelhirsch Software GmbH
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#include "StoragePage.h"
#include "Box.h"
#include "CircularProgressBar.h"
#include "Diagram.h"
#include "EnergyMeter.h"
#include "StorageBar.h"
#include "StorageMeter.h"
#include <QTimer>
#include <QskAnimator.h>
#include <QskBox.h>
#include <QskBoxShapeMetrics.h>
#include <QskGradient.h>
#include <QskGradientStop.h>
#include <QskGraphicLabel.h>
#include <QskProgressBar.h>
#include <QskPushButton.h>
#include <QskSkin.h>
#include <QskStackBox.h>
#include <QskTextLabel.h>
QSK_SUBCONTROL( StoragePage, Panel )
struct StorageRowAnimator final : public QObject, public QskAnimator
{
explicit StorageRowAnimator( QQuickWindow* const window, QObject* parent )
: QObject( parent )
{
setEasingCurve( QEasingCurve::InQuad );
setWindow( window );
setDuration( 400 );
}
void advance( qreal value ) override
{
callback( value );
}
std::function< void( qreal ) > callback = []( qreal ) {};
};
StoragePage::StoragePage( QQuickItem* const parent )
: QskLinearBox( Qt::Vertical, parent )
{
setPanel( true );
setSizePolicy( QskSizePolicy::Expanding, QskSizePolicy::Expanding );
setDefaultAlignment( Qt::AlignTop );
setSpacing( 24 );
setMargins( 30 );
setSizePolicy( Qt::Horizontal, QskSizePolicy::Minimum );
setSubcontrolProxy( QskBox::Panel, StoragePage::Panel );
addRow( "Backup (B:)", "Used for daily backups", 0.1, 0.1, 0.1, 0.02, 0.01 );
addRow( "Share (S:)", "Used for sharing files publicly", 0.05, 0.05, 0.2, 0.2, 0.01 );
addRow( "Exchange (X:)", "Used for exchanging large files", 0.1, 0.1, 0.1, 0.1, 0.5 );
addSpacer( 1, 99 );
}
void StoragePage::addRow( const QString& title, const QString& description,
qreal pictures, qreal music, qreal videos, qreal documents, qreal others )
{
Storage storage;
storage.title = title;
storage.description = description;
storage.distribution.pictures = pictures;
storage.distribution.music = music;
storage.distribution.videos = videos;
storage.distribution.documents = documents;
storage.distribution.others = others;
auto* const box = new Box( "Network Storage", this );
auto* const layout = new QskLinearBox( Qt::Horizontal, box );
auto* const left = new QskLinearBox( Qt::Vertical, layout );
left->setDefaultAlignment( Qt::AlignCenter );
auto* const center = new QskLinearBox( Qt::Vertical, layout );
left->setDefaultAlignment( Qt::AlignLeft );
auto* const right = new QskLinearBox( Qt::Vertical, layout );
layout->setStretchFactor( left, 1 );
layout->setStretchFactor( center, 2 );
layout->setStretchFactor( right, 5 );
const auto percent = 100.0 * ( 1.0 - storage.distribution.free() );
auto* const meter = new StorageMeter( left );
meter->setValue( percent );
meter->setMinimumSize( 64, 64 );
meter->setMaximumSize( 64, 64 );
auto* const maintitle = new QskTextLabel( storage.title, center );
maintitle->setFontRole( QskSkin::LargeFont );
auto* const subtitle = new QskTextLabel( storage.description, center );
subtitle->setFontRole( QskSkin::MediumFont );
const auto& media = storage.distribution;
auto* const bar = new StorageBar( right );
bar->setPictures( media.pictures );
bar->setMusic( media.music );
bar->setVideos( media.videos );
bar->setDocuments( media.documents );
bar->setOthers( media.others );
auto* const legend = new QskLinearBox( Qt::Horizontal, right );
legend->setSpacing( 12 );
legend->addSpacer( 1, 999 );
auto* const sync = new QskPushButton( "Update", legend );
sync->setFontRoleHint( QskPushButton::Text, QskSkin::SmallFont );
using S = StorageBar;
for ( const auto& pair : QVector< QPair< QString, QskGradient > >{
{ QStringLiteral( "Picture" ), bar->gradientHint( S::Pictures ) },
{ QStringLiteral( "Music" ), bar->gradientHint( S::Music ) },
{ QStringLiteral( "Videos" ), bar->gradientHint( S::Videos ) },
{ QStringLiteral( "Documents" ), bar->gradientHint( S::Documents ) },
{ QStringLiteral( "Others" ), bar->gradientHint( S::Others ) },
{ QStringLiteral( "Free" ), bar->gradientHint( S::Free ) } } )
{
constexpr int size = 8;
auto* const dot = new QskBox( legend );
dot->setBoxShapeHint( QskBox::Panel, { size / 2 } );
dot->setMinimumSize( size, size );
dot->setMaximumSize( size, size );
dot->setGradientHint( QskBox::Panel, pair.second );
auto* const label = new QskTextLabel( pair.first, legend );
label->setFontRole( QskSkin::SmallFont );
}
auto* const animator = new StorageRowAnimator( window(), sync );
animator->callback = [ meter, bar, media ]( qreal v ) {
meter->setValue( 100 * ( 1.0 - media.free() ) * v );
bar->setPictures( media.pictures * v );
bar->setMusic( media.music * v );
bar->setVideos( media.videos * v );
bar->setDocuments( media.documents * v );
bar->setOthers( media.others * v );
};
connect( sync, &QskPushButton::clicked, animator, [ animator ]() { animator->start(); } );
}

View File

@ -0,0 +1,50 @@
/******************************************************************************
* Copyright (C) 2022 Edelhirsch Software GmbH
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#pragma once
#include <QVector>
#include <QskLinearBox.h>
#include <memory>
class QQuickItem;
class StoragePage final : public QskLinearBox
{
public:
QSK_SUBCONTROLS( Panel )
explicit StoragePage( QQuickItem* parent = nullptr );
private:
struct Storage
{
struct Media
{
qreal pictures = 0;
qreal music = 0;
qreal videos = 0;
qreal documents = 0;
qreal others = 0;
inline constexpr bool operator==( const Media& rhs ) const noexcept
{
return pictures == rhs.pictures && music == rhs.music && videos == rhs.videos &&
documents == rhs.documents && others == rhs.others;
}
inline constexpr qreal free() const noexcept
{
return 1.0 - pictures - music - videos - documents - others;
}
};
QString title;
QString description;
Media distribution;
};
void addRow( const QString& title, const QString& description,
qreal pictures, qreal music, qreal videos, qreal documents, qreal others );
};

View File

@ -4,7 +4,7 @@
*****************************************************************************/
#include "TopBar.h"
#include "PieChartPainted.h"
#include "EnergyMeter.h"
#include <QskSkin.h>
#include <QskTextLabel.h>
@ -62,7 +62,7 @@ TopBarItem::TopBarItem(
const auto subcontrol = subcontrolForIndex( index );
const auto textColor = color( subcontrol | QskAspect::TextColor );
auto pieChart = new PieChartPainted(
auto pieChart = new EnergyMeter(
textColor, gradient, progress, pieChartAndDisplay );
pieChart->setSizePolicy( Qt::Horizontal, QskSizePolicy::Constrained );

View File

@ -1,20 +1,20 @@
<RCC>
<qresource prefix="/">
<file>images/main-icon.svg</file>
<file>images/dashboard.svg</file>
<file>images/rooms.svg</file>
<file>images/devices.svg</file>
<file>images/statistics.svg</file>
<file>images/storage.svg</file>
<file>images/members.svg</file>
<file>images/logout.svg</file>
<file>images/indoor-temperature.svg</file>
<file>images/humidity.svg</file>
<file>images/up.svg</file>
<file>images/down.svg</file>
<file>images/lamps.svg</file>
<file>images/music-system.svg</file>
<file>images/ac.svg</file>
<file>images/router.svg</file>
<qresource>
<file>images/qvg/main-icon.qvg</file>
<file>images/qvg/dashboard.qvg</file>
<file>images/qvg/rooms.qvg</file>
<file>images/qvg/devices.qvg</file>
<file>images/qvg/statistics.qvg</file>
<file>images/qvg/storage.qvg</file>
<file>images/qvg/members.qvg</file>
<file>images/qvg/logout.qvg</file>
<file>images/qvg/indoor-temperature.qvg</file>
<file>images/qvg/humidity.qvg</file>
<file>images/qvg/up.qvg</file>
<file>images/qvg/down.qvg</file>
<file>images/qvg/lamps.qvg</file>
<file>images/qvg/music-system.qvg</file>
<file>images/qvg/ac.qvg</file>
<file>images/qvg/router.qvg</file>
</qresource>
</RCC>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 782 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 317 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 247 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 239 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 799 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 603 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 747 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 251 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 322 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 275 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 925 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 225 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 262 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 B

View File

@ -1,34 +1,36 @@
CONFIG += qskexample
QT += svg
QT += quick_private # TODO: examples should not use private headers
SOURCES += \
Box.cpp \
BoxWithButtons.cpp \
CircularProgressBar.cpp \
CircularProgressBarSkinlet.cpp \
DashboardPage.cpp \
DevicesPage.cpp \
Diagram.cpp \
DiagramSkinlet.cpp \
EnergyMeter.cpp \
GraphicProvider.cpp \
GridBox.cpp \
LightDisplaySkinlet.cpp \
LightDisplay.cpp \
MainItem.cpp \
MainWindow.cpp \
MenuBar.cpp \
MembersPage.cpp \
MyDevices.cpp \
PieChart.cpp \
PieChartPainted.cpp \
PieChartSkinlet.cpp \
RoomsPage.cpp \
RoundedIcon.cpp \
Skin.cpp \
StatisticsPage.cpp \
TopBar.cpp \
RoundButton.cpp \
UsageBox.cpp \
UsageDiagram.cpp \
MainWindow.cpp \
StoragePage.cpp \
StorageMeter.cpp \
StorageBar.cpp \
StorageBarSkinlet.cpp \
main.cpp \
SOURCES += \
@ -43,25 +45,30 @@ HEADERS += \
CircularProgressBarSkinlet.h \
Diagram.h \
DiagramSkinlet.h \
EnergyMeter.h \
GraphicProvider.h \
GridBox.h \
LightDisplaySkinlet.h \
LightDisplay.h \
DashboardPage.h \
DevicesPage.h \
MainItem.h \
MainWindow.h \
MembersPage.h \
MenuBar.h \
MyDevices.h \
PieChart.h \
PieChartPainted.h \
PieChartSkinlet.h \
RoomsPage.h \
RoundedIcon.h \
Skin.h \
StatisticsPage.h \
TopBar.h \
RoundButton.h \
UsageBox.h \
UsageDiagram.h
UsageDiagram.h \
StoragePage.h \
StorageMeter.h \
StorageBar.h \
StorageBarSkinlet.h \
HEADERS += \
nodes/DiagramDataNode.h \

Some files were not shown because too many files have changed in this diff Show More