iot storage page
This commit is contained in:
parent
f4aaf4cc92
commit
a5cf5acad9
|
@ -19,6 +19,7 @@
|
|||
#include "RoomsPage.h"
|
||||
#include "RoundedIcon.h"
|
||||
#include "RoundButton.h"
|
||||
#include "StoragePage.h"
|
||||
#include "TopBar.h"
|
||||
#include "UsageBox.h"
|
||||
#include "UsageDiagram.h"
|
||||
|
@ -241,6 +242,7 @@ void Skin::initHints( const Palette& palette )
|
|||
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 );
|
||||
QskShadowMetrics shadowMetrics( 0, 10 );
|
||||
|
|
|
@ -0,0 +1,207 @@
|
|||
#include "StorageBar.h"
|
||||
#include <QskBox.h>
|
||||
#include <QskBoxShapeMetrics.h>
|
||||
#include <QskSkinlet.h>
|
||||
#include <QskAnimator.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 )
|
||||
|
||||
class StorageBarSkinlet final : public QskSkinlet
|
||||
{
|
||||
Q_GADGET
|
||||
public:
|
||||
|
||||
using Inherited = QskSkinlet;
|
||||
enum NodeRole { Pictures, Music, Videos, Documents, Others, Free };
|
||||
Q_INVOKABLE StorageBarSkinlet( QskSkin* skin = nullptr ) : Inherited(skin)
|
||||
{
|
||||
setNodeRoles( { Pictures, Music, Videos, Documents, Others, Free } );
|
||||
setOwnedBySkinnable(true);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
QRectF subControlRect( const QskSkinnable* skinnable, const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const override
|
||||
{
|
||||
using S = StorageBar;
|
||||
const auto bar = static_cast< const S* >( skinnable );
|
||||
|
||||
auto x = contentsRect.x();
|
||||
const auto y = contentsRect.y();
|
||||
const auto h = contentsRect.height();
|
||||
|
||||
const QRectF p {x, y, contentsRect.width() * bar->pictures(), h};
|
||||
if(subControl == S::Pictures){ return p; }
|
||||
x += p.width();
|
||||
|
||||
const QRectF m {x, y, contentsRect.width() * bar->music(), h};
|
||||
if(subControl == S::Music){ return m; }
|
||||
x += m.width();
|
||||
|
||||
const QRectF v {x, y, contentsRect.width() * bar->videos(), h};
|
||||
if(subControl == S::Videos){ return v; }
|
||||
x += v.width();
|
||||
|
||||
const QRectF d {x, y, contentsRect.width() * bar->documents(), h};
|
||||
if(subControl == S::Documents){ return d; }
|
||||
x += d.width();
|
||||
|
||||
const QRectF o {x, y, contentsRect.width() * bar->others(), h};
|
||||
if(subControl == S::Others){ return o; }
|
||||
x += o.width();
|
||||
|
||||
const QRectF f {x, y, contentsRect.width() * bar->free(), h};
|
||||
if(subControl == S::Free){ return f; }
|
||||
|
||||
return Inherited::subControlRect( skinnable, contentsRect, subControl );
|
||||
}
|
||||
|
||||
QSGNode* updateSubNode( const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node) const override
|
||||
{
|
||||
using S = StorageBar;
|
||||
const auto bar = static_cast< const S* >( skinnable );
|
||||
|
||||
if ( nodeRole == Pictures)
|
||||
{
|
||||
const QskGradient g( { { 0.0, bar->color(S::Pictures).lighter() },{ 1.0, bar->color(S::Pictures) } } );
|
||||
return updateBoxNode( bar, node, bar->subControlRect( S::Pictures ), g, S::Pictures );
|
||||
}
|
||||
|
||||
if ( nodeRole == Music)
|
||||
{
|
||||
const QskGradient g( { { 0.0, bar->color(S::Music).lighter() },{ 1.0, bar->color(S::Music) } } );
|
||||
return updateBoxNode( bar, node, bar->subControlRect( S::Music ), g, S::Music );
|
||||
}
|
||||
|
||||
if ( nodeRole == Videos)
|
||||
{
|
||||
const QskGradient g( { { 0.0, bar->color(S::Videos).lighter() },{ 1.0, bar->color(S::Videos) } } );
|
||||
return updateBoxNode( bar, node, bar->subControlRect( S::Videos ), g, S::Videos );
|
||||
}
|
||||
|
||||
if ( nodeRole == Documents)
|
||||
{
|
||||
const QskGradient g( { { 0.0, bar->color(S::Documents).lighter() },{ 1.0, bar->color(S::Documents) } } );
|
||||
return updateBoxNode( bar, node, bar->subControlRect( S::Documents ), g, S::Documents );
|
||||
}
|
||||
|
||||
if ( nodeRole == Others)
|
||||
{
|
||||
const QskGradient g( { { 0.0, bar->color(S::Others).lighter() },{ 1.0, bar->color(S::Others) } } );
|
||||
return updateBoxNode( bar, node, bar->subControlRect( S::Others ), g, S::Others );
|
||||
}
|
||||
|
||||
if ( nodeRole == Free)
|
||||
{
|
||||
const QskGradient g( { { 0.0, bar->color(S::Free).lighter() },{ 1.0, bar->color(S::Free)} } );
|
||||
return updateBoxNode( bar, node, bar->subControlRect( S::Free ), g, S::Free );
|
||||
}
|
||||
|
||||
return Inherited::updateSubNode( skinnable, nodeRole, node );
|
||||
}
|
||||
};
|
||||
|
||||
StorageBar::StorageBar(QskQuickItem * const parent) : Inherited(parent)
|
||||
{
|
||||
setSkinlet(new StorageBarSkinlet());
|
||||
|
||||
using S = StorageBar;
|
||||
|
||||
// TODO move into skin?
|
||||
setColor(S::Pictures, "#FFBE0B");
|
||||
setColor(S::Music,"#FB5607");
|
||||
setColor(S::Videos,"#FF006E");
|
||||
setColor(S::Documents, "#8338EC");
|
||||
setColor(S::Others, "#3A86FF");
|
||||
setColor(S::Free, "lightgray");
|
||||
|
||||
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;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
#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;
|
||||
qreal m_music;
|
||||
qreal m_videos;
|
||||
qreal m_documents;
|
||||
qreal m_others;
|
||||
};
|
|
@ -0,0 +1,46 @@
|
|||
#include "StorageMeter.h"
|
||||
#include "CircularProgressBar.h"
|
||||
#include <QskTextLabel.h>
|
||||
|
||||
QSK_SUBCONTROL( StorageMeter, Fill )
|
||||
|
||||
StorageMeter::StorageMeter(QQuickItem *parent) noexcept
|
||||
: EnergyMeter(QColor{}, QskGradient{}, 0, parent)
|
||||
{
|
||||
const auto gradient = gradientHint(StorageMeter::Fill);
|
||||
setGradientHint(StorageMeter::Fill, QskGradient(QskGradientStops{
|
||||
{0.0,Qt::green},
|
||||
{0.5,"darkorange"},
|
||||
{1.0,Qt::red}
|
||||
}));
|
||||
}
|
||||
|
||||
qreal StorageMeter::progress() const noexcept
|
||||
{
|
||||
if( auto* const bar = findChild<CircularProgressBar*>() )
|
||||
{
|
||||
return bar->value() / 100.0;
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
void StorageMeter::setProgress(qreal progress) noexcept
|
||||
{
|
||||
const auto value = qBound(0.0, progress, 1.0);
|
||||
|
||||
const auto gradient = gradientHint(StorageMeter::Fill);
|
||||
|
||||
const auto color = gradient.extracted( value, value ).startColor();
|
||||
|
||||
if( auto* const bar = findChild<CircularProgressBar*>() )
|
||||
{
|
||||
bar->setGradientHint( CircularProgressBar::Bar, {color, color.darker(100)});
|
||||
bar->setValue(value * 100.0);
|
||||
}
|
||||
|
||||
if ( auto* const label = findChild<QskTextLabel*>() )
|
||||
{
|
||||
label->setTextColor( color );
|
||||
label->setText( locale().toString( static_cast<int>(value * 100.0) ) + " " + locale().percent() );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include "EnergyMeter.h"
|
||||
#include <QskGradient.h>
|
||||
|
||||
class StorageMeter final : public EnergyMeter
|
||||
{
|
||||
public:
|
||||
QSK_SUBCONTROLS( Fill )
|
||||
explicit StorageMeter(QQuickItem* parent = nullptr) noexcept;
|
||||
qreal progress() const noexcept;
|
||||
public Q_SLOTS:
|
||||
void setProgress(qreal progress) noexcept;
|
||||
};
|
|
@ -1,21 +1,148 @@
|
|||
/******************************************************************************
|
||||
* Copyright (C) 2021 Edelhirsch Software GmbH
|
||||
* This file may be used under the terms of the 3-clause BSD License
|
||||
*****************************************************************************/
|
||||
|
||||
#include "StoragePage.h"
|
||||
|
||||
#include "CircularProgressBar.h"
|
||||
#include "Box.h"
|
||||
#include "EnergyMeter.h"
|
||||
#include "Diagram.h"
|
||||
#include "StorageMeter.h"
|
||||
#include "StorageBar.h"
|
||||
#include <QskAnimator.h>
|
||||
#include <QskSkin.h>
|
||||
#include <QskGraphicLabel.h>
|
||||
#include <QskStackBox.h>
|
||||
#include <QskTextLabel.h>
|
||||
#include <QskGradient.h>
|
||||
#include <QskGradientStop.h>
|
||||
#include <QskBox.h>
|
||||
#include <QskBoxShapeMetrics.h>
|
||||
#include <QskPushButton.h>
|
||||
#include <QTimer>
|
||||
|
||||
QSK_SUBCONTROL( StoragePage, Panel )
|
||||
|
||||
StoragePage::StoragePage( QQuickItem* parent )
|
||||
: QskLinearBox( Qt::Vertical, parent )
|
||||
{
|
||||
auto* const textLabel = new QskTextLabel( "storage page", this );
|
||||
textLabel->setAlignmentHint( QskTextLabel::Text, Qt::AlignCenter );
|
||||
textLabel->setFontRole( QskSkin::HugeFont );
|
||||
}
|
||||
struct Media {
|
||||
qreal pictures = 0;
|
||||
qreal music = 0;
|
||||
qreal videos = 0;
|
||||
qreal documents = 0;
|
||||
qreal others = 0;
|
||||
|
||||
#include "moc_StoragePage.cpp"
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
StoragePage::StoragePage(QQuickItem * const parent) : QskLinearBox(Qt::Vertical, parent)
|
||||
{
|
||||
const auto createProgressBar = [](const qreal value, QQuickItem* const parent)
|
||||
{
|
||||
auto* const bar = new StorageMeter(parent);
|
||||
bar->setProgress(value);
|
||||
bar->setMinimumSize(16,16);
|
||||
bar->setMaximumSize(64,64);
|
||||
bar->setSizePolicy( QskSizePolicy::Preferred, QskSizePolicy::Constrained );
|
||||
return bar;
|
||||
};
|
||||
|
||||
const auto createLinearBox = [](Qt::Orientation orientation = Qt::Vertical, QskSizePolicy::Policy hp = QskSizePolicy::Fixed , QskSizePolicy::Policy vp = QskSizePolicy::Fixed, QQuickItem* const parent = nullptr){
|
||||
auto* const layout = new QskLinearBox(orientation, parent);
|
||||
layout->setSizePolicy( hp, vp );
|
||||
return layout;
|
||||
};
|
||||
|
||||
const auto createRow = [&](const QString& titleText, const QString& subTitleText, const Media& media, QQuickItem* const parent){
|
||||
auto* const box = new Box("Network Storage", parent);
|
||||
auto* const layout = new QskLinearBox(Qt::Horizontal, box);
|
||||
auto* const left = new QskLinearBox(Qt::Vertical, layout);
|
||||
auto* const center = new QskLinearBox(Qt::Vertical, layout);
|
||||
auto* const right = new QskLinearBox(Qt::Vertical, layout);
|
||||
auto* const stack = new QskStackBox(left);
|
||||
stack->setAutoLayoutChildren(true);
|
||||
const auto percent = 1.0 - media.free();
|
||||
auto* const bar = createProgressBar(percent, createLinearBox(Qt::Vertical, QskSizePolicy::Preferred, QskSizePolicy::Preferred, stack));
|
||||
|
||||
stack->addItem(bar);
|
||||
stack->setCurrentItem(bar);
|
||||
auto* title = new QskTextLabel(titleText, center);
|
||||
title->setFontRole(QskSkin::LargeFont);
|
||||
auto* subtitle = new QskTextLabel(subTitleText, center);
|
||||
subtitle->setFontRole(QskSkin::MediumFont);
|
||||
center->addSpacer(1,99);
|
||||
|
||||
auto* const storageBar = new StorageBar(right);
|
||||
storageBar->setPictures(media.pictures);
|
||||
storageBar->setMusic(media.music);
|
||||
storageBar->setVideos(media.videos);
|
||||
storageBar->setDocuments(media.documents);
|
||||
storageBar->setOthers(media.others);
|
||||
|
||||
auto* const mediaLegend = new QskLinearBox(Qt::Horizontal, right);
|
||||
mediaLegend->setSpacing(12);
|
||||
mediaLegend->addSpacer(1,999);
|
||||
auto* const sync = new QskPushButton("Update", mediaLegend);
|
||||
sync->setFontRoleHint(QskPushButton::Text, QskSkin::SmallFont);
|
||||
connect(sync, &QskPushButton::clicked, storageBar, [bar, storageBar, media](){
|
||||
struct PropertyAnimator final : public QskAnimator
|
||||
{
|
||||
void advance( qreal value ) override { callback(value); }
|
||||
void done() override { delete this; }
|
||||
std::function<void(qreal)> callback = [](qreal){};
|
||||
};
|
||||
|
||||
auto* const animator = new PropertyAnimator();
|
||||
animator->setEasingCurve(QEasingCurve::InQuad);
|
||||
animator->setWindow(storageBar->window());
|
||||
animator->callback = [bar, storageBar, media](qreal v){
|
||||
bar->setProgress((1.0 - media.free()) * v);
|
||||
storageBar->setPictures(media.pictures * v);
|
||||
storageBar->setMusic(media.music * v);
|
||||
storageBar->setVideos(media.videos * v);
|
||||
storageBar->setDocuments(media.documents * v);
|
||||
storageBar->setOthers(media.others * v);
|
||||
};
|
||||
animator->setDuration(400);
|
||||
animator->start();
|
||||
});
|
||||
|
||||
using S = StorageBar;
|
||||
const auto subcontrols = QVector<QskAspect>{S::Pictures, S::Music, S::Videos, S::Documents, S::Others, S::Free};
|
||||
const auto subcontrolNames = QStringList{"Picture", "Music", "Videos", "Documents", "Others", "Free"};
|
||||
Q_ASSERT(subcontrolNames.size() == subcontrols.size());
|
||||
|
||||
for(int i = 0; i < subcontrolNames.size(); ++i)
|
||||
{
|
||||
auto* const dot = new QskBox(mediaLegend);
|
||||
dot->setBoxShapeHint(QskBox::Panel,{4});
|
||||
dot->setMinimumSize(8,8);
|
||||
dot->setMaximumSize(8,8);
|
||||
const auto color = storageBar->color(subcontrols[i]);
|
||||
dot->setGradientHint(QskBox::Panel, {color.lighter(), color});
|
||||
auto* const label = new QskTextLabel(subcontrolNames[i], mediaLegend);
|
||||
label->setFontRole(QskSkin::SmallFont);
|
||||
}
|
||||
|
||||
layout->setStretchFactor(left,1);
|
||||
layout->setStretchFactor(center,2);
|
||||
layout->setStretchFactor(right,5);
|
||||
return layout;
|
||||
};
|
||||
|
||||
setPanel( true );
|
||||
setSizePolicy( QskSizePolicy::Expanding, QskSizePolicy::Expanding );
|
||||
setDefaultAlignment( Qt::AlignTop );
|
||||
setSpacing( 24 );
|
||||
setMargins(30);
|
||||
setSizePolicy(Qt::Horizontal, QskSizePolicy::Minimum);
|
||||
|
||||
setSubcontrolProxy( QskBox::Panel, StoragePage::Panel );
|
||||
|
||||
createRow("Backup (B:)","Used for daily backups", Media{0.1,0.1,0.1,0.02, 0.01}, this);
|
||||
createRow("Share (S:)","Used for sharing files publicly",Media{0.05,0.05,0.2,0.2,0.01}, this);
|
||||
createRow("Exchange (X:)","Used for exchanging large files", Media{0.1,0.1,0.1,0.1,0.5}, this);
|
||||
addSpacer(1, 99);
|
||||
}
|
||||
|
|
|
@ -28,6 +28,9 @@ SOURCES += \
|
|||
RoundButton.cpp \
|
||||
UsageBox.cpp \
|
||||
UsageDiagram.cpp \
|
||||
StoragePage.cpp \
|
||||
StorageMeter.cpp \
|
||||
StorageBar.cpp \
|
||||
main.cpp \
|
||||
|
||||
SOURCES += \
|
||||
|
@ -62,7 +65,10 @@ HEADERS += \
|
|||
TopBar.h \
|
||||
RoundButton.h \
|
||||
UsageBox.h \
|
||||
UsageDiagram.h
|
||||
UsageDiagram.h \
|
||||
StoragePage.h \
|
||||
StorageMeter.h \
|
||||
StorageBar.h \
|
||||
|
||||
HEADERS += \
|
||||
nodes/DiagramDataNode.h \
|
||||
|
|
Loading…
Reference in New Issue