Merge branch 'master' into arcrenderer2

This commit is contained in:
Uwe Rathmann 2024-09-09 09:57:35 +02:00
commit 7f0e0126be
20 changed files with 238 additions and 651 deletions

View File

@ -159,6 +159,7 @@ void ProgressBarPage::populate()
{ {
auto* ring = new QskProgressRing( determinateRingsHBox ); auto* ring = new QskProgressRing( determinateRingsHBox );
ring->setSize( size ); ring->setSize( size );
ring->setLayoutAlignmentHint( Qt::AlignCenter );
QQuickItem* parentItem; QQuickItem* parentItem;

View File

@ -6,11 +6,8 @@
set(SOURCES set(SOURCES
Box.h Box.cpp Box.h Box.cpp
BoxWithButtons.h BoxWithButtons.cpp BoxWithButtons.h BoxWithButtons.cpp
CircularProgressBar.h CircularProgressBar.cpp
CircularProgressBarSkinlet.h CircularProgressBarSkinlet.cpp
Diagram.h Diagram.cpp Diagram.h Diagram.cpp
DiagramSkinlet.h DiagramSkinlet.cpp DiagramSkinlet.h DiagramSkinlet.cpp
EnergyMeter.h EnergyMeter.cpp
GraphicProvider.h GraphicProvider.cpp GraphicProvider.h GraphicProvider.cpp
GridBox.h GridBox.cpp GridBox.h GridBox.cpp
LightDisplaySkinlet.h LightDisplaySkinlet.cpp LightDisplaySkinlet.h LightDisplaySkinlet.cpp
@ -31,7 +28,7 @@ set(SOURCES
UsageBox.h UsageBox.cpp UsageBox.h UsageBox.cpp
UsageDiagram.h UsageDiagram.cpp UsageDiagram.h UsageDiagram.cpp
StoragePage.h StoragePage.cpp StoragePage.h StoragePage.cpp
StorageMeter.h StorageMeter.cpp ValueMeter.h ValueMeter.cpp
StorageBar.h StorageBar.cpp StorageBar.h StorageBar.cpp
StorageBarSkinlet.h StorageBarSkinlet.cpp StorageBarSkinlet.h StorageBarSkinlet.cpp
nodes/DiagramDataNode.h nodes/DiagramDataNode.cpp nodes/DiagramDataNode.h nodes/DiagramDataNode.cpp

View File

@ -1,197 +0,0 @@
/******************************************************************************
* Copyright (C) 2021 Edelhirsch Software GmbH
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "CircularProgressBar.h"
#include <QskAnimator.h>
#include <QskFunctions.h>
QSK_SUBCONTROL( CircularProgressBar, Groove )
QSK_SUBCONTROL( CircularProgressBar, Bar )
namespace
{
class PositionAnimator : public QskAnimator
{
public:
PositionAnimator( CircularProgressBar* progressBar )
: m_progressBar( progressBar )
{
setAutoRepeat( true );
setDuration( 1300 );
setWindow( progressBar->window() );
}
void advance( qreal value ) override
{
const auto aspect = CircularProgressBar::Bar | QskAspect::Position;
m_progressBar->setMetric( aspect, value );
m_progressBar->update();
}
private:
CircularProgressBar* m_progressBar;
};
}
class CircularProgressBar::PrivateData
{
public:
void updateIndeterminateAnimator( CircularProgressBar* progressBar )
{
if ( !isIndeterminate )
{
delete animator;
animator = nullptr;
return;
}
if ( progressBar->window() && progressBar->isVisible() )
{
if ( animator == nullptr )
animator = new PositionAnimator( progressBar );
animator->start();
}
else
{
if ( animator )
animator->stop();
}
}
PositionAnimator* animator = nullptr;
qreal value = 0.0;
qreal origin = 0.0;
bool hasOrigin = false;
bool isIndeterminate = false;
};
CircularProgressBar::~CircularProgressBar() = default;
CircularProgressBar::CircularProgressBar( qreal min, qreal max, QQuickItem* parent )
: QskBoundedControl( min, max, parent )
, m_data( new PrivateData )
{
m_data->value = minimum();
initSizePolicy( QskSizePolicy::MinimumExpanding, QskSizePolicy::MinimumExpanding );
connect( this, &QskBoundedControl::boundariesChanged,
this, &CircularProgressBar::adjustValue );
}
CircularProgressBar::CircularProgressBar( QQuickItem* parent )
: CircularProgressBar( 0.0, 100.0, parent )
{
}
bool CircularProgressBar::isIndeterminate() const
{
return m_data->isIndeterminate;
}
void CircularProgressBar::setIndeterminate( bool on )
{
if ( on == m_data->isIndeterminate )
return;
m_data->isIndeterminate = on;
m_data->updateIndeterminateAnimator( this );
update();
Q_EMIT indeterminateChanged( on );
}
void CircularProgressBar::resetOrigin()
{
if ( m_data->hasOrigin )
{
m_data->hasOrigin = false;
update();
Q_EMIT originChanged( origin() );
}
}
qreal CircularProgressBar::origin() const
{
if ( m_data->hasOrigin )
{
return boundedValue( m_data->origin );
}
return minimum();
}
qreal CircularProgressBar::value() const
{
return m_data->value;
}
qreal CircularProgressBar::valueAsRatio() const
{
return QskBoundedControl::valueAsRatio( m_data->value );
}
void CircularProgressBar::setValue( qreal value )
{
if ( isComponentComplete() )
value = boundedValue( value );
setValueInternal( value );
}
void CircularProgressBar::setValueAsRatio( qreal ratio )
{
ratio = qBound( 0.0, ratio, 1.0 );
setValue( minimum() + ratio * boundaryLength() );
}
void CircularProgressBar::setOrigin( qreal origin )
{
if ( isComponentComplete() )
origin = boundedValue( origin );
if( !m_data->hasOrigin || !qskFuzzyCompare( m_data->origin, origin ) )
{
m_data->hasOrigin = true;
m_data->origin = origin;
update();
Q_EMIT originChanged( origin );
}
}
void CircularProgressBar::componentComplete()
{
Inherited::componentComplete();
adjustValue();
}
void CircularProgressBar::setValueInternal( qreal value )
{
if ( !qskFuzzyCompare( value, m_data->value ) )
{
m_data->value = value;
Q_EMIT valueChanged( value );
update();
}
}
void CircularProgressBar::adjustValue()
{
if ( isComponentComplete() )
setValueInternal( boundedValue( m_data->value ) );
}
#include "moc_CircularProgressBar.cpp"

View File

@ -1,61 +0,0 @@
/******************************************************************************
* Copyright (C) 2021 Edelhirsch Software GmbH
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#pragma once
#include <QskBoundedControl.h>
class CircularProgressBar : public QskBoundedControl
{
Q_OBJECT
Q_PROPERTY( bool indeterminate READ isIndeterminate
WRITE setIndeterminate NOTIFY indeterminateChanged )
Q_PROPERTY( qreal origin READ origin
WRITE setOrigin RESET resetOrigin NOTIFY originChanged )
Q_PROPERTY( qreal value READ value WRITE setValue NOTIFY valueChanged )
Q_PROPERTY( qreal valueAsRatio READ valueAsRatio
WRITE setValueAsRatio NOTIFY valueChanged )
using Inherited = QskBoundedControl;
public:
QSK_SUBCONTROLS( Groove, Bar )
CircularProgressBar( qreal min, qreal max, QQuickItem* parent = nullptr );
CircularProgressBar( QQuickItem* parent = nullptr );
~CircularProgressBar() override;
bool isIndeterminate() const;
void setIndeterminate( bool on = true );
void resetOrigin();
qreal origin() const;
qreal value() const;
qreal valueAsRatio() const; // [0.0, 1.0]
public Q_SLOTS:
void setValue( qreal );
void setValueAsRatio( qreal );
void setOrigin( qreal );
Q_SIGNALS:
void indeterminateChanged( bool );
void valueChanged( qreal );
void originChanged( qreal );
protected:
void componentComplete() override;
private:
void setValueInternal( qreal value );
void adjustValue();
class PrivateData;
std::unique_ptr< PrivateData > m_data;
};

View File

@ -1,49 +0,0 @@
/******************************************************************************
* Copyright (C) 2021 Edelhirsch Software GmbH
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "CircularProgressBarSkinlet.h"
#include "CircularProgressBar.h"
CircularProgressBarSkinlet::CircularProgressBarSkinlet( QskSkin* skin )
: QskSkinlet( skin )
{
setNodeRoles( { GrooveRole, BarRole } );
}
CircularProgressBarSkinlet::~CircularProgressBarSkinlet()
{
}
QRectF CircularProgressBarSkinlet::subControlRect(
const QskSkinnable*, const QRectF& contentsRect, QskAspect::Subcontrol ) const
{
return contentsRect;
}
QSGNode* CircularProgressBarSkinlet::updateSubNode(
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const
{
switch( nodeRole )
{
case GrooveRole:
{
return updateArcNode( skinnable, node, CircularProgressBar::Groove );
}
case BarRole:
{
const auto bar = static_cast< const CircularProgressBar* >( skinnable );
const qreal startAngle = 90.0;
const qreal spanAngle = 360.0 * bar->valueAsRatio();
return updateArcNode( skinnable, node, startAngle, -spanAngle,
CircularProgressBar::Bar );
}
}
return Inherited::updateSubNode( skinnable, nodeRole, node );
}
#include "moc_CircularProgressBarSkinlet.cpp"

View File

@ -1,36 +0,0 @@
/******************************************************************************
* Copyright (C) 2021 Edelhirsch Software GmbH
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#pragma once
#include <QskSkinlet.h>
class CircularProgressBar;
class CircularProgressBarSkinlet : public QskSkinlet
{
Q_GADGET
using Inherited = QskSkinlet;
public:
enum NodeRole
{
GrooveRole,
BarRole,
RoleCount,
};
Q_INVOKABLE CircularProgressBarSkinlet( QskSkin* = nullptr );
~CircularProgressBarSkinlet() override;
QRectF subControlRect( const QskSkinnable*,
const QRectF&, QskAspect::Subcontrol ) const override;
protected:
QSGNode* updateSubNode( const QskSkinnable*,
quint8 nodeRole, QSGNode* ) const override;
};

View File

@ -1,69 +0,0 @@
/******************************************************************************
* Copyright (C) 2021 Edelhirsch Software GmbH
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "EnergyMeter.h"
#include "CircularProgressBar.h"
#include <QskTextLabel.h>
#include <QskFontRole.h>
namespace
{
class ValueLabel : public QskTextLabel
{
public:
ValueLabel( QQuickItem* parent )
: QskTextLabel( parent )
{
initSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed );
setLayoutAlignmentHint( Qt::AlignCenter );
setFontRole( QskFontRole::Caption );
}
void setValue( int value )
{
setText( locale().toString( value ) + " " + locale().percent() );
}
};
}
EnergyMeter::EnergyMeter( const QColor& textColor,
const QskGradient& gradient, int value, QQuickItem* parent )
: QskControl( parent )
{
setAutoLayoutChildren( true );
auto valueBar = new CircularProgressBar( this );
valueBar->setGradientHint( CircularProgressBar::Bar, gradient );
valueBar->setValue( value );
auto valueLabel = new ValueLabel( this );
valueLabel->setTextColor( textColor );
valueLabel->setValue( value );
}
QSizeF EnergyMeter::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

@ -1,18 +0,0 @@
/******************************************************************************
* Copyright (C) 2021 Edelhirsch Software GmbH
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#pragma once
#include <QskControl.h>
class EnergyMeter : public QskControl
{
public:
EnergyMeter( const QColor&, const QskGradient&,
int progress, QQuickItem* parent = nullptr );
protected:
QSizeF contentsSizeHint( Qt::SizeHint, const QSizeF& ) const override;
};

View File

@ -7,8 +7,6 @@
#include "Box.h" #include "Box.h"
#include "BoxWithButtons.h" #include "BoxWithButtons.h"
#include "CircularProgressBar.h"
#include "CircularProgressBarSkinlet.h"
#include "DashboardPage.h" #include "DashboardPage.h"
#include "Diagram.h" #include "Diagram.h"
#include "DiagramSkinlet.h" #include "DiagramSkinlet.h"
@ -21,7 +19,6 @@
#include "RoundedIcon.h" #include "RoundedIcon.h"
#include "StorageBar.h" #include "StorageBar.h"
#include "StorageBarSkinlet.h" #include "StorageBarSkinlet.h"
#include "StorageMeter.h"
#include "StoragePage.h" #include "StoragePage.h"
#include "TopBar.h" #include "TopBar.h"
#include "UsageBox.h" #include "UsageBox.h"
@ -37,6 +34,7 @@
#include <QskSkinHintTableEditor.h> #include <QskSkinHintTableEditor.h>
#include <QskStateCombination.h> #include <QskStateCombination.h>
#include <QskTextLabel.h> #include <QskTextLabel.h>
#include <QskProgressRing.h>
#include <QskGraphicLabel.h> #include <QskGraphicLabel.h>
#include <QskFontRole.h> #include <QskFontRole.h>
@ -56,7 +54,6 @@ Skin::Skin( QObject* parent )
{ {
setObjectName( "iot" ); setObjectName( "iot" );
declareSkinlet< CircularProgressBar, CircularProgressBarSkinlet >();
declareSkinlet< Diagram, DiagramSkinlet >(); declareSkinlet< Diagram, DiagramSkinlet >();
declareSkinlet< LightDisplay, LightDisplaySkinlet >(); declareSkinlet< LightDisplay, LightDisplaySkinlet >();
declareSkinlet< StorageBar, StorageBarSkinlet >(); declareSkinlet< StorageBar, StorageBarSkinlet >();
@ -87,9 +84,9 @@ void Skin::initHints()
ed.setPadding( MainContentGridBox::Panel, { 19, 0, 27, 24 } ); ed.setPadding( MainContentGridBox::Panel, { 19, 0, 27, 24 } );
{
// menu bar: // menu bar:
{
using Q = QskPushButton; using Q = QskPushButton;
using A = QskAspect; using A = QskAspect;
@ -113,7 +110,9 @@ void Skin::initHints()
ed.setAlignment( Q::Icon | A::Header, Qt::AlignCenter ); ed.setAlignment( Q::Icon | A::Header, Qt::AlignCenter );
} }
{
// top bar: // top bar:
ed.setPadding( TopBar::Panel, { 25, 35, 25, 0 } ); ed.setPadding( TopBar::Panel, { 25, 35, 25, 0 } );
ed.setColor( TopBarItem::Item1 | QskAspect::TextColor, 0xffff3122 ); ed.setColor( TopBarItem::Item1 | QskAspect::TextColor, 0xffff3122 );
@ -121,17 +120,17 @@ void Skin::initHints()
ed.setColor( TopBarItem::Item3 | QskAspect::TextColor, 0xfff99055 ); ed.setColor( TopBarItem::Item3 | QskAspect::TextColor, 0xfff99055 );
ed.setColor( TopBarItem::Item4 | QskAspect::TextColor, 0xff6776ff ); ed.setColor( TopBarItem::Item4 | QskAspect::TextColor, 0xff6776ff );
// arcs are counterclockwise, so specify the 2nd color first: ed.setGradient( TopBarItem::Item1, 0xffff5c00, 0xffff3122 );
ed.setGradient( TopBarItem::Item1, 0xffff3122, 0xffff5c00 ); ed.setGradient( TopBarItem::Item2, 0xff6776ff, 0xff6100ff );
ed.setGradient( TopBarItem::Item2, 0xff6100ff, 0xff6776ff ); ed.setGradient( TopBarItem::Item3, 0xffffce50, 0xffff3122 );
ed.setGradient( TopBarItem::Item3, 0xffff3122, 0xffffce50 ); ed.setGradient( TopBarItem::Item4, 0xff6776ff, 0xff6100ff );
ed.setGradient( TopBarItem::Item4, 0xff6100ff, 0xff6776ff ); }
// the bar gradient is defined through the top bar items above // the bar gradient is defined through the top bar items above
ed.setArcMetrics( CircularProgressBar::Groove, 90, -360, 8.53 ); ed.setArcMetrics( QskProgressRing::Groove, 90, -360, 8.53 );
// the span angle will be set in the progress bar, we just give a dummy // the span angle will be set in the progress bar, we just give a dummy
// value here: // value here:
ed.setArcMetrics( CircularProgressBar::Bar, 90, -180, 8.53 ); ed.setArcMetrics( QskProgressRing::Fill, ed.arcMetrics( QskProgressRing::Groove ) );
ed.setFontRole( TimeTitleLabel::Text, { QskFontRole::Caption, QskFontRole::High } ); ed.setFontRole( TimeTitleLabel::Text, { QskFontRole::Caption, QskFontRole::High } );
@ -283,8 +282,8 @@ void Skin::initHints()
ed.setColor( QskTextLabel::Text, palette.text ); ed.setColor( QskTextLabel::Text, palette.text );
ed.setColor( UsageDiagramBox::DayText, palette.text ); ed.setColor( UsageDiagramBox::DayText, palette.text );
ed.setMetric( CircularProgressBar::Groove | QskAspect::Border, 2 ); ed.setMetric( QskProgressRing::Groove | QskAspect::Border, 2 );
ed.setColor( CircularProgressBar::Groove | QskAspect::Border, ed.setColor( QskProgressRing::Groove | QskAspect::Border,
palette.circularProgressBarGroove ); palette.circularProgressBarGroove );
// storage bar // storage bar
@ -302,9 +301,13 @@ void Skin::initHints()
// storage meter // storage meter
{ {
ed.setGradient( StorageMeter::Status, ed.setGradient( StoragePage::Status,
{ { { 0.00, "#00ff00" }, { 0.33, "#00ff00" }, { 0.33, "#ffaf00" }, { 0.66, "#ffaf00" }, { {
{ 0.66, "#ff0000" }, { 1.00, "#ff0000" } } } ); { 0.00, "#00ff00" }, { 0.33, "#00ff00" },
{ 0.33, "#ffaf00" }, { 0.66, "#ffaf00" },
{ 0.66, "#ff0000" }, { 1.00, "#ff0000" }
} }
);
} }
} }

View File

@ -1,65 +0,0 @@
/******************************************************************************
* Copyright (C) 2022 Edelhirsch Software GmbH
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "StorageMeter.h"
#include "CircularProgressBar.h"
#include <QskFontRole.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( QskFontRole::Caption );
}
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

@ -1,22 +0,0 @@
/******************************************************************************
* Copyright (C) 2022 Edelhirsch Software GmbH
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#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

@ -6,7 +6,7 @@
#include "StoragePage.h" #include "StoragePage.h"
#include "Box.h" #include "Box.h"
#include "StorageBar.h" #include "StorageBar.h"
#include "StorageMeter.h" #include "ValueMeter.h"
#include <QTimer> #include <QTimer>
#include <QskAnimator.h> #include <QskAnimator.h>
#include <QskBox.h> #include <QskBox.h>
@ -20,6 +20,60 @@
#include <QskTextLabel.h> #include <QskTextLabel.h>
QSK_SUBCONTROL( StoragePage, Panel ) QSK_SUBCONTROL( StoragePage, Panel )
QSK_SUBCONTROL( StoragePage, Status )
namespace
{
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;
};
class StorageMeter final : public ValueMeter
{
public:
StorageMeter( QQuickItem* parent = nullptr )
: ValueMeter( parent )
{
setFixedSize( 64, 64 );
connect( this, &ValueMeter::valueChanged,
this, &StorageMeter::setStatusColor );
}
private:
void setStatusColor( qreal value )
{
const auto color = qskInterpolatedColorAt(
gradientHint( StoragePage::Status ).stops(), value / 100.0 );
setFillGradient( { color, color.lighter() } );
setTextColor( color );
}
};
}
struct StorageRowAnimator final : public QObject, public QskAnimator struct StorageRowAnimator final : public QObject, public QskAnimator
{ {
@ -85,8 +139,6 @@ void StoragePage::addRow( const QString& title, const QString& description,
const auto percent = 100.0 * ( 1.0 - storage.distribution.free() ); const auto percent = 100.0 * ( 1.0 - storage.distribution.free() );
auto* const meter = new StorageMeter( left ); auto* const meter = new StorageMeter( left );
meter->setValue( percent ); meter->setValue( percent );
meter->setMinimumSize( 64, 64 );
meter->setMaximumSize( 64, 64 );
auto* const maintitle = new QskTextLabel( storage.title, center ); auto* const maintitle = new QskTextLabel( storage.title, center );
maintitle->setFontRole( QskFontRole::Headline ); maintitle->setFontRole( QskFontRole::Headline );
@ -136,5 +188,6 @@ void StoragePage::addRow( const QString& title, const QString& description,
bar->setDocuments( media.documents * v ); bar->setDocuments( media.documents * v );
bar->setOthers( media.others * v ); bar->setOthers( media.others * v );
}; };
connect( sync, &QskPushButton::clicked, animator, [ animator ]() { animator->start(); } ); connect( sync, &QskPushButton::clicked,
animator, [ animator ]() { animator->start(); } );
} }

View File

@ -7,44 +7,15 @@
#include <QVector> #include <QVector>
#include <QskLinearBox.h> #include <QskLinearBox.h>
#include <memory>
class QQuickItem;
class StoragePage final : public QskLinearBox class StoragePage final : public QskLinearBox
{ {
public: public:
QSK_SUBCONTROLS( Panel ) QSK_SUBCONTROLS( Panel, Status )
explicit StoragePage( QQuickItem* parent = nullptr );
StoragePage( QQuickItem* parent = nullptr );
private: 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, void addRow( const QString& title, const QString& description,
qreal pictures, qreal music, qreal videos, qreal documents, qreal others ); qreal pictures, qreal music, qreal videos, qreal documents, qreal others );
}; };

View File

@ -4,7 +4,7 @@
*****************************************************************************/ *****************************************************************************/
#include "TopBar.h" #include "TopBar.h"
#include "EnergyMeter.h" #include "ValueMeter.h"
#include <QskFontRole.h> #include <QskFontRole.h>
#include <QskTextLabel.h> #include <QskTextLabel.h>
@ -41,6 +41,22 @@ namespace
return TopBarItem::Item4; return TopBarItem::Item4;
} }
} }
class EnergyMeter : public ValueMeter
{
public:
EnergyMeter( const QColor& textColor,
const QskGradient& gradient, int value, QQuickItem* parent )
: ValueMeter( parent )
{
setFillGradient( gradient );
setValue( value );
setTextColor( textColor );
setFixedSize( 57, 57 );
}
};
} }
TopBarItem::TopBarItem( TopBarItem::TopBarItem(
@ -62,9 +78,7 @@ TopBarItem::TopBarItem(
const auto subcontrol = subcontrolForIndex( index ); const auto subcontrol = subcontrolForIndex( index );
const auto textColor = color( subcontrol | QskAspect::TextColor ); const auto textColor = color( subcontrol | QskAspect::TextColor );
auto pieChart = new EnergyMeter( (void) new EnergyMeter( textColor, gradient, progress, pieChartAndDisplay );
textColor, gradient, progress, pieChartAndDisplay );
pieChart->setSizePolicy( Qt::Horizontal, QskSizePolicy::Constrained );
auto display = new QskLinearBox( Qt::Vertical, pieChartAndDisplay ); auto display = new QskLinearBox( Qt::Vertical, pieChartAndDisplay );
display->setSpacing( 0 ); display->setSpacing( 0 );

View File

@ -0,0 +1,42 @@
/******************************************************************************
* Copyright (C) 2022 Edelhirsch Software GmbH
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "ValueMeter.h"
#include <QskFontRole.h>
#include <QskTextLabel.h>
ValueMeter::ValueMeter( QQuickItem* parent )
: QskProgressRing( parent )
{
setAutoLayoutChildren( true );
initSizePolicy( QskSizePolicy::MinimumExpanding, QskSizePolicy::Constrained );
m_label = new QskTextLabel( this );
m_label->setSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed );
m_label->setLayoutAlignmentHint( Qt::AlignCenter );
m_label->setFontRole( QskFontRole::Caption );
connect( this, &QskProgressRing::valueChanged,
this, &ValueMeter::updateMeter );
updateMeter( value() );
}
void ValueMeter::updateMeter( const qreal value )
{
m_label->setText( text( value ) );
}
QString ValueMeter::text( qreal value ) const
{
value = static_cast< int >( value );
return locale().toString( value ) + ' ' + locale().percent();
}
void ValueMeter::setTextColor( const QColor& color )
{
m_label->setTextColor( color );
}

View File

@ -0,0 +1,25 @@
/******************************************************************************
* Copyright (C) 2022 Edelhirsch Software GmbH
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#pragma once
#include <QskProgressRing.h>
class QskTextLabel;
class ValueMeter : public QskProgressRing
{
public:
ValueMeter( QQuickItem* parent = nullptr );
void setTextColor( const QColor& );
protected:
virtual QString text( qreal ) const;
private:
void updateMeter( qreal value );
QskTextLabel* m_label = nullptr;
};

View File

@ -15,13 +15,13 @@ using Q = QskProgressBar;
namespace namespace
{ {
QskIntervalF qskFillInterval( const Q* bar ) QskIntervalF qskFillInterval( const QskProgressIndicator* indicator )
{ {
qreal pos1, pos2; qreal pos1, pos2;
if ( bar->isIndeterminate() ) if ( indicator->isIndeterminate() )
{ {
const auto pos = bar->positionHint( QskProgressIndicator::Fill ); const auto pos = indicator->positionHint( QskProgressIndicator::Fill );
static const QEasingCurve curve( QEasingCurve::InOutCubic ); static const QEasingCurve curve( QEasingCurve::InOutCubic );
@ -32,10 +32,11 @@ namespace
} }
else else
{ {
pos1 = bar->valueAsRatio( bar->origin() ); pos1 = indicator->valueAsRatio( indicator->origin() );
pos2 = bar->valueAsRatio( bar->value() ); pos2 = indicator->valueAsRatio( indicator->value() );
} }
auto bar = static_cast< const QskProgressBar* >( indicator );
if( bar->orientation() == Qt::Horizontal ) if( bar->orientation() == Qt::Horizontal )
{ {
if ( bar->layoutMirroring() ) if ( bar->layoutMirroring() )
@ -107,11 +108,11 @@ QSGNode* QskProgressBarSkinlet::updateFillNode(
const auto subControl = Q::Fill; const auto subControl = Q::Fill;
const auto rect = bar->subControlRect( subControl ); const auto rect = indicator->subControlRect( subControl );
if ( rect.isEmpty() ) if ( rect.isEmpty() )
return nullptr; return nullptr;
auto gradient = bar->gradientHint( subControl ); auto gradient = indicator->gradientHint( subControl );
if ( !gradient.isVisible() ) if ( !gradient.isVisible() )
return nullptr; return nullptr;

View File

@ -4,7 +4,6 @@
*****************************************************************************/ *****************************************************************************/
#include "QskProgressRing.h" #include "QskProgressRing.h"
#include "QskIntervalF.h" #include "QskIntervalF.h"
QSK_SUBCONTROL( QskProgressRing, Groove ) QSK_SUBCONTROL( QskProgressRing, Groove )
@ -20,6 +19,8 @@ QskProgressRing::QskProgressRing( qreal min, qreal max, QQuickItem* parent )
: Inherited( min, max, parent ) : Inherited( min, max, parent )
, m_data( new PrivateData ) , m_data( new PrivateData )
{ {
initSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed );
m_data->size = NormalSize; m_data->size = NormalSize;
setSubcontrolProxy( Inherited::Groove, Groove ); setSubcontrolProxy( Inherited::Groove, Groove );

View File

@ -10,31 +10,6 @@
using Q = QskProgressRing; using Q = QskProgressRing;
namespace
{
QskIntervalF qskFillInterval( const Q* ring )
{
qreal pos1, pos2;
if ( ring->isIndeterminate() )
{
const auto pos = ring->positionHint( QskProgressIndicator::Fill );
pos1 = pos2 = pos;
}
else
{
pos1 = ring->valueAsRatio( ring->origin() );
pos2 = ring->valueAsRatio( ring->value() );
}
if ( pos1 > pos2 )
std::swap( pos1, pos2 );
return QskIntervalF( pos1, pos2 );
}
}
QskProgressRingSkinlet::QskProgressRingSkinlet( QskSkin* skin ) QskProgressRingSkinlet::QskProgressRingSkinlet( QskSkin* skin )
: Inherited( skin ) : Inherited( skin )
{ {
@ -48,27 +23,8 @@ QRectF QskProgressRingSkinlet::subControlRect(
const QskSkinnable* skinnable, const QRectF& contentsRect, const QskSkinnable* skinnable, const QRectF& contentsRect,
QskAspect::Subcontrol subControl ) const QskAspect::Subcontrol subControl ) const
{ {
const auto ring = static_cast< const Q* >( skinnable );
if( subControl == Q::Groove || subControl == Q::Fill ) if( subControl == Q::Groove || subControl == Q::Fill )
{ return contentsRect;
auto rect = contentsRect;
const auto size = ring->strutSizeHint( Q::Fill );
if( ring->layoutMirroring() )
{
rect.setLeft( rect.right() - size.width() );
}
else
{
rect.setWidth( size.width() );
}
rect.setTop( rect.top() + 0.5 * ( rect.height() - size.height() ) );
rect.setHeight( size.height() );
return rect;
}
return Inherited::subControlRect( skinnable, contentsRect, subControl ); return Inherited::subControlRect( skinnable, contentsRect, subControl );
} }
@ -90,36 +46,74 @@ QSGNode* QskProgressRingSkinlet::updateFillNode(
if ( rect.isEmpty() ) if ( rect.isEmpty() )
return nullptr; return nullptr;
const auto metrics = ring->arcMetricsHint( subControl );
if ( metrics.isNull() )
return nullptr;
auto gradient = ring->gradientHint( subControl ); auto gradient = ring->gradientHint( subControl );
if ( !gradient.isVisible() ) if ( !gradient.isVisible() )
return nullptr; return nullptr;
const auto intv = fillInterval( ring );
if ( ( gradient.type() == QskGradient::Stops ) && !gradient.isMonochrome() ) if ( ( gradient.type() == QskGradient::Stops ) && !gradient.isMonochrome() )
{ {
const auto center = rect.center(); const auto stops = qskExtractedGradientStops( gradient.stops(),
const auto arcMetrics = ring->arcMetricsHint( Q::Fill ); intv.lowerBound(), intv.upperBound() );
gradient.setConicDirection( center.x(), center.y(), arcMetrics.startAngle(), arcMetrics.spanAngle() );
gradient.setStops( stops );
if ( metrics.spanAngle() < 0.0 )
gradient.reverse();
} }
const auto interval = qskFillInterval( ring ); const auto startAngle = metrics.startAngle() + intv.lowerBound() * metrics.spanAngle();
const auto arcMetrics = ring->arcMetricsHint( subControl ); const auto spanAngle = intv.upperBound() * metrics.spanAngle();
const auto startAngle = arcMetrics.startAngle() + interval.lowerBound() * arcMetrics.spanAngle();
const auto spanAngle = interval.upperBound() * arcMetrics.spanAngle();
return updateArcNode( ring, node, rect, gradient, startAngle, spanAngle, subControl ); return updateArcNode( ring, node, rect, gradient, startAngle, spanAngle, subControl );
} }
QSizeF QskProgressRingSkinlet::sizeHint( const QskSkinnable* skinnable, QSizeF QskProgressRingSkinlet::sizeHint( const QskSkinnable* skinnable,
Qt::SizeHint which, const QSizeF& ) const Qt::SizeHint which, const QSizeF& constraint ) const
{ {
if ( which != Qt::PreferredSize ) if ( which != Qt::PreferredSize )
return QSizeF(); return QSizeF();
const auto ring = static_cast< const Q* >( skinnable ); auto hint = skinnable->strutSizeHint( Q::Fill );
hint = hint.expandedTo( skinnable->strutSizeHint( Q::Groove ) );
const auto r = ring->strutSizeHint( Q::Fill ); if ( !constraint.isEmpty() )
return r; {
const qreal aspectRatio = hint.isEmpty() ? 1.0 : hint.width() / hint.height();
if ( constraint.width() >= 0.0 )
hint.setHeight( constraint.width() / aspectRatio );
else
hint.setWidth( constraint.height() * aspectRatio );
}
return hint;
}
QskIntervalF QskProgressRingSkinlet::fillInterval(
const QskProgressIndicator* indicator ) const
{
qreal pos1, pos2;
if ( indicator->isIndeterminate() )
{
pos1 = pos2 = indicator->positionHint( QskProgressIndicator::Fill );
}
else
{
pos1 = indicator->valueAsRatio( indicator->origin() );
pos2 = indicator->valueAsRatio( indicator->value() );
}
if ( pos1 > pos2 )
std::swap( pos1, pos2 );
return QskIntervalF( pos1, pos2 );
} }
#include "moc_QskProgressRingSkinlet.cpp" #include "moc_QskProgressRingSkinlet.cpp"

View File

@ -8,7 +8,7 @@
#include "QskProgressIndicatorSkinlet.h" #include "QskProgressIndicatorSkinlet.h"
class QskProgressRing; class QskIntervalF;
class QSK_EXPORT QskProgressRingSkinlet : public QskProgressIndicatorSkinlet class QSK_EXPORT QskProgressRingSkinlet : public QskProgressIndicatorSkinlet
{ {
@ -29,6 +29,8 @@ class QSK_EXPORT QskProgressRingSkinlet : public QskProgressIndicatorSkinlet
protected: protected:
QSGNode* updateGrooveNode( const QskProgressIndicator*, QSGNode* ) const override; QSGNode* updateGrooveNode( const QskProgressIndicator*, QSGNode* ) const override;
QSGNode* updateFillNode( const QskProgressIndicator*, QSGNode* ) const override; QSGNode* updateFillNode( const QskProgressIndicator*, QSGNode* ) const override;
QskIntervalF fillInterval( const QskProgressIndicator* ) const;
}; };
#endif #endif