IOT dashboard: Implement rooms page

This commit is contained in:
Peter Hartmann 2022-07-14 14:43:21 +02:00 committed by uwerat
parent cfab871ad8
commit ee4f47c0c8
10 changed files with 257 additions and 148 deletions

View File

@ -82,7 +82,7 @@ DashboardPage::DashboardPage( QQuickItem* parent )
gridBox->addItem( new IndoorTemperature(), 0, 1 ); gridBox->addItem( new IndoorTemperature(), 0, 1 );
gridBox->addItem( new Humidity(), 1, 1 ); gridBox->addItem( new Humidity(), 1, 1 );
gridBox->addItem( new MyDevices(), 0, 2, 2, 1 ); gridBox->addItem( new MyDevices(), 0, 2, 2, 1 );
gridBox->addItem( new UsageDiagramBox(), 2, 0, 0, 2 ); gridBox->addItem( new UsageDiagramBox( QString(), new UsageDiagram ), 2, 0, 0, 2 );
gridBox->addItem( new LightIntensity(), 2, 2 ); gridBox->addItem( new LightIntensity(), 2, 2 );
gridBox->setColumnStretchFactor( 0, 37 ); // factors add up to 100 gridBox->setColumnStretchFactor( 0, 37 ); // factors add up to 100

View File

@ -8,11 +8,14 @@
QSK_SUBCONTROL( Diagram, Chart ) QSK_SUBCONTROL( Diagram, Chart )
QSK_SUBCONTROL( Diagram, Segments ) QSK_SUBCONTROL( Diagram, Segments )
QSK_SUBCONTROL( Diagram, ChartLine1 ) QSK_SUBCONTROL( Diagram, ChartLine1 )
QSK_SUBCONTROL( Diagram, ChartArea1 )
QSK_SUBCONTROL( Diagram, ChartLine2 ) QSK_SUBCONTROL( Diagram, ChartLine2 )
QSK_SUBCONTROL( Diagram, ChartArea2 )
QSK_SUBCONTROL( Diagram, ChartLine3 ) QSK_SUBCONTROL( Diagram, ChartLine3 )
QSK_SUBCONTROL( Diagram, ChartArea1 )
QSK_SUBCONTROL( Diagram, ChartArea2 )
QSK_SUBCONTROL( Diagram, ChartArea3 ) QSK_SUBCONTROL( Diagram, ChartArea3 )
QSK_SUBCONTROL( Diagram, ChartBar1 )
QSK_SUBCONTROL( Diagram, ChartBar2 )
QSK_SUBCONTROL( Diagram, ChartBar3 )
class Diagram::PrivateData class Diagram::PrivateData
{ {

View File

@ -14,13 +14,16 @@ class Diagram : public QskControl
using Inherited = QskControl; using Inherited = QskControl;
public: public:
QSK_SUBCONTROLS( Chart, Segments, ChartLine1, ChartArea1, QSK_SUBCONTROLS( Chart, Segments,
ChartLine2, ChartArea2, ChartLine3, ChartArea3 ) ChartLine1, ChartArea1, ChartLine2,
ChartArea2, ChartLine3, ChartArea3,
ChartBar1, ChartBar2, ChartBar3 )
enum Type enum Type
{ {
Line = 0x01, Line = 0x01,
Area = 0x02, Area = 0x02,
Bar = 0x04,
}; };
Q_DECLARE_FLAGS( Types, Type ) Q_DECLARE_FLAGS( Types, Type )

View File

@ -8,36 +8,35 @@
#include "nodes/DiagramDataNode.h" #include "nodes/DiagramDataNode.h"
#include "nodes/DiagramSegmentsNode.h" #include "nodes/DiagramSegmentsNode.h"
#include <QskBoxNode.h>
namespace namespace
{ {
QskAspect::Subcontrol areaForIndex( int i ) QskAspect::Subcontrol subcontrolForIndex( Diagram::Type type, int i )
{ {
switch( i ) QskAspect::Subcontrol subcontrols[] = {
Diagram::ChartLine1, Diagram::ChartLine2, Diagram::ChartLine3,
Diagram::ChartArea1, Diagram::ChartArea2, Diagram::ChartArea3,
Diagram::ChartBar1, Diagram::ChartBar2, Diagram::ChartBar3 };
int row;
switch( type )
{ {
case 1: case Diagram::Line:
return Diagram::ChartArea2; row = 0;
break;
case 2: case Diagram::Area:
return Diagram::ChartArea3; row = 1;
break;
default: case Diagram::Bar:
return Diagram::ChartArea1; row = 2;
} break;
} }
QskAspect::Subcontrol lineForIndex( int i ) return subcontrols[ row * 3 + i ];
{
switch( i )
{
case 1:
return Diagram::ChartLine2;
case 2:
return Diagram::ChartLine3;
default:
return Diagram::ChartLine1;
}
} }
} }
@ -96,7 +95,7 @@ QSGNode* DiagramSkinlet::updateChartNode( const Diagram* diagram, QSGNode* node
const QRectF rect = diagram->subControlRect( Q::Chart ); const QRectF rect = diagram->subControlRect( Q::Chart );
const qreal yMax = diagram->yMax(); const qreal yMax = diagram->yMax();
const QVector< Diagram::Type > types = { Diagram::Line, Diagram::Area }; const QVector< Diagram::Type > types = { Diagram::Line, Diagram::Area, Diagram::Bar };
for( int i = 0; i < diagram->dataPoints().size(); ++i ) for( int i = 0; i < diagram->dataPoints().size(); ++i )
{ {
@ -114,13 +113,66 @@ QSGNode* DiagramSkinlet::updateChartNode( const Diagram* diagram, QSGNode* node
const QVector< QPointF > dataPoints = diagram->dataPoints().at( i ); const QVector< QPointF > dataPoints = diagram->dataPoints().at( i );
int nodeIndex = 0; int nodeIndex = 0;
QskAspect::Subcontrol lineSubcontrol = lineForIndex( i ); QskAspect::Subcontrol lineSubcontrol = subcontrolForIndex( Diagram::Line, i );
QskAspect::Subcontrol areaSubcontrol = areaForIndex( i ); QskAspect::Subcontrol areaSubcontrol = subcontrolForIndex( Diagram::Area, i );
QskAspect::Subcontrol barSubcontrol = subcontrolForIndex( Diagram::Bar, i );
int lineWidth = diagram->metric( lineSubcontrol | QskAspect::Size ); int lineWidth = diagram->metric( lineSubcontrol | QskAspect::Size );
for( int j = 0; j < types.size(); ++j ) for( int j = 0; j < types.size(); ++j )
{ {
if( diagram->typesAt( i ) & types.at( j ) ) const auto type = types.at( j );
if( diagram->typesAt( i ) & type )
{
QColor color;
if( type == Diagram::Bar )
{
QSGNode* barsNode;
if( chartNode->childCount() > nodeIndex )
{
barsNode = chartNode->childAtIndex( nodeIndex );
}
else
{
barsNode = new QSGNode;
chartNode->appendChildNode( barsNode );
}
for( int k = 0; k < dataPoints.size(); ++k )
{
QskBoxNode* barNode;
if( barsNode->childCount() > k )
{
barNode = static_cast< QskBoxNode* >( barsNode->childAtIndex( k ) );
}
else
{
barNode = new QskBoxNode;
barsNode->appendChildNode( barNode );
}
const auto& dataPoint = dataPoints.at( k );
const auto size = diagram->strutSizeHint( barSubcontrol );
const qreal xMin = dataPoints.at( 0 ).x();
const qreal xMax = dataPoints.at( dataPoints.count() - 1 ).x();
const qreal x = ( ( dataPoint.x() - xMin ) / ( xMax - xMin ) ) * rect.width()
+ i * size.width();
const qreal fraction = ( dataPoint.y() / yMax ) * rect.height();
const qreal y = rect.height() - fraction;
QRectF barRect( x, y, size.width(), fraction );
color = diagram->color( barSubcontrol );
qDebug() << x << y << nodeIndex;
barNode->setBoxData( barRect, color );
}
}
else
{ {
DiagramDataNode* dataPointNode; DiagramDataNode* dataPointNode;
@ -134,15 +186,26 @@ QSGNode* DiagramSkinlet::updateChartNode( const Diagram* diagram, QSGNode* node
chartNode->appendChildNode( dataPointNode ); chartNode->appendChildNode( dataPointNode );
} }
const DiagramDataNode::Type nodeType = ( types.at( j ) == Diagram::Line ) ? DiagramDataNode::Line : DiagramDataNode::Area; DiagramDataNode::Type nodeType;
const QColor color = ( types.at( j ) == Diagram::Line ) ? diagram->color( lineSubcontrol )
: diagram->color( areaSubcontrol ); if( type == Diagram::Line )
{
nodeType = DiagramDataNode::Line;
color = diagram->color( lineSubcontrol );
}
else
{
nodeType = DiagramDataNode::Area;
color = diagram->color( areaSubcontrol );
}
dataPointNode->update( rect, nodeType, color, dataPoints, yMax, false, lineWidth ); dataPointNode->update( rect, nodeType, color, dataPoints, yMax, false, lineWidth );
nodeIndex++;
} }
} }
nodeIndex++;
}
while( nodeIndex < chartNode->childCount() ) while( nodeIndex < chartNode->childCount() )
{ {
chartNode->removeChildNode( chartNode->childAtIndex( nodeIndex++ ) ); chartNode->removeChildNode( chartNode->childAtIndex( nodeIndex++ ) );

View File

@ -2,6 +2,7 @@
#include "DashboardPage.h" #include "DashboardPage.h"
#include "MenuBar.h" #include "MenuBar.h"
#include "RoomsPage.h"
#include <QskGesture.h> #include <QskGesture.h>
#include <QskEvent.h> #include <QskEvent.h>
@ -16,6 +17,7 @@ MainItem::MainItem( QQuickItem* parent )
: QskControl( parent ) : QskControl( parent )
, m_cube( new QskStackBox( false, this ) ) , m_cube( new QskStackBox( false, this ) )
, m_mainLayout( new QskLinearBox( Qt::Horizontal, m_cube ) ) , m_mainLayout( new QskLinearBox( Qt::Horizontal, m_cube ) )
, m_otherLayout( new QskLinearBox( Qt::Horizontal, m_cube ) )
{ {
setAutoLayoutChildren( true ); setAutoLayoutChildren( true );
setAcceptedMouseButtons( Qt::LeftButton ); setAcceptedMouseButtons( Qt::LeftButton );
@ -27,10 +29,18 @@ MainItem::MainItem( QQuickItem* parent )
m_mainLayout->setSpacing( 0 ); m_mainLayout->setSpacing( 0 );
m_otherLayout->setSpacing( 0 );
(void) new MenuBar( m_mainLayout ); (void) new MenuBar( m_mainLayout );
(void) new DashboardPage( m_mainLayout ); (void) new DashboardPage( m_mainLayout );
(void) new MenuBar( m_otherLayout );
(void) new RoomsPage( m_otherLayout );
m_cube->addItem( m_mainLayout ); m_cube->addItem( m_mainLayout );
m_cube->addItem( m_otherLayout );
m_cube->setCurrentItem( m_mainLayout );
} }
void MainItem::gestureEvent( QskGestureEvent* event ) void MainItem::gestureEvent( QskGestureEvent* event )

View File

@ -23,5 +23,6 @@ class MainItem : public QskControl
private: private:
QskStackBox* m_cube; QskStackBox* m_cube;
QskLinearBox* m_mainLayout; QskLinearBox* m_mainLayout;
QskLinearBox* m_otherLayout;
QskPanGestureRecognizer m_panRecognizer; QskPanGestureRecognizer m_panRecognizer;
}; };

View File

@ -7,6 +7,7 @@
#include "Box.h" #include "Box.h"
#include "BoxWithButtons.h" #include "BoxWithButtons.h"
#include "Diagram.h"
#include "GridBox.h" #include "GridBox.h"
#include "LightDisplay.h" #include "LightDisplay.h"
#include "MyDevices.h" #include "MyDevices.h"
@ -30,33 +31,44 @@ QSK_SUBCONTROL( RoomsPage, Panel )
namespace namespace
{ {
class IndoorTemperature : public BoxWithButtons class RoomsDiagram : public Diagram
{ {
public: public:
IndoorTemperature( QQuickItem* parent = nullptr ) RoomsDiagram( QQuickItem* parent = nullptr )
: BoxWithButtons( "Indoor Temperature", "+24", true, parent ) : Diagram( parent )
{ {
} const qreal water[] =
{
10, 20, 30, 40, 50, 60, 70
}; };
class Humidity : public BoxWithButtons const qreal electricity[] =
{ {
public: 10, 20, 30, 40, 50, 60, 70
Humidity( QQuickItem* parent = nullptr )
: BoxWithButtons( "Humidity", "30%", false, parent )
{
}
}; };
class LightIntensity : public Box const qreal gas[] =
{ {
public: 10, 20, 30, 40, 50, 60, 70
LightIntensity( QQuickItem* parent = nullptr ) };
: Box( "Light intensity", parent )
addCurve( water, sizeof( water ) / sizeof( qreal ) );
addCurve( electricity, sizeof( electricity ) / sizeof( qreal ) );
addCurve( gas, sizeof( gas ) / sizeof( qreal ) );
setYMax( 100 );
}
private:
void addCurve( const qreal values[], const size_t count )
{ {
addSpacer( 5 ); QVector< QPointF > points;
auto* lightDisplay = new LightDisplay( this ); points.reserve( count );
lightDisplay->setValue( 50.0 );
for( size_t i = 0; i < count; i++ )
points += QPointF( i, values[i] );
addDataPoints( points, Diagram::Bar );
} }
}; };
} }
@ -72,19 +84,16 @@ RoomsPage::RoomsPage( QQuickItem* parent )
setDefaultAlignment( Qt::AlignTop ); setDefaultAlignment( Qt::AlignTop );
setSpacing( 24 ); setSpacing( 24 );
auto topBar = new TopBar();
auto gridBox = new MainContentGridBox(); auto gridBox = new MainContentGridBox();
gridBox->setPadding( 30 );
gridBox->setPanel( true ); gridBox->setPanel( true );
gridBox->setSpacing( 15 ); gridBox->setSpacing( 15 );
gridBox->addItem( new UsageBox(), 0, 0, 2, 1 ); gridBox->addItem( new UsageDiagramBox( "Living Room", new RoomsDiagram() ), 0, 0 );
gridBox->addItem( new UsageDiagramBox( "Bedroom", new RoomsDiagram() ), 0, 1 );
gridBox->addItem( new UsageDiagramBox( "Bathroom", new RoomsDiagram() ), 1, 0 );
gridBox->addItem( new UsageDiagramBox( "Kitchen", new RoomsDiagram() ), 1, 1 );
gridBox->setColumnStretchFactor( 0, 37 ); // factors add up to 100
gridBox->setColumnStretchFactor( 1, 37 );
gridBox->setColumnStretchFactor( 2, 26 );
addItem( topBar );
addItem( gridBox ); addItem( gridBox );
} }

View File

@ -182,6 +182,18 @@ void Skin::initHints( const Palette& palette )
ed.setColor( Diagram::ChartArea2, "#66ff3122" ); ed.setColor( Diagram::ChartArea2, "#66ff3122" );
ed.setColor( Diagram::ChartArea3, "#66ff7d34" ); ed.setColor( Diagram::ChartArea3, "#66ff7d34" );
ed.setColor( Diagram::ChartBar1, 0xff6776ff );
ed.setColor( Diagram::ChartBar2, 0xffff3122 );
ed.setColor( Diagram::ChartBar3, 0xffff7d34 );
ed.setStrutSize( Diagram::ChartBar1, { 6, -1 } );
ed.setStrutSize( Diagram::ChartBar2, { 6, -1 } );
ed.setStrutSize( Diagram::ChartBar3, { 6, -1 } );
ed.setBoxShape( Diagram::ChartBar1, { 100, 100, 0, 0, Qt::RelativeSize } );
ed.setBoxShape( Diagram::ChartBar2, { 100, 100, 0, 0, Qt::RelativeSize } );
ed.setBoxShape( Diagram::ChartBar3, { 100, 100, 0, 0, Qt::RelativeSize } );
// light intensity: // light intensity:
ed.setBoxShape( LightDisplay::Panel, 100, Qt::RelativeSize ); ed.setBoxShape( LightDisplay::Panel, 100, Qt::RelativeSize );

View File

@ -59,11 +59,22 @@ namespace
} }
}; };
}
class UsageDiagram : public Diagram UsageDiagramLegend::UsageDiagramLegend( QQuickItem* parent )
: QskLinearBox( parent )
{ {
public: initSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed );
UsageDiagram( QQuickItem* parent = nullptr )
setMargins( 10, 10, 20, 10 );
setSpacing( 30 );
addItem( new LegendItem( UsageDiagramLegend::Water ) );
addItem( new LegendItem( UsageDiagramLegend::Electricity ) );
addItem( new LegendItem( UsageDiagramLegend::Gas ) );
}
UsageDiagram::UsageDiagram( QQuickItem* parent )
: Diagram( parent ) : Diagram( parent )
{ {
// These values are calculated with a boost::math::cubic_b_spline. // These values are calculated with a boost::math::cubic_b_spline.
@ -118,8 +129,7 @@ namespace
setYMax( 100 ); setYMax( 100 );
} }
private: void UsageDiagram::addCurve( const qreal values[], const size_t count )
void addCurve( const qreal values[], const size_t count )
{ {
QVector< QPointF > points; QVector< QPointF > points;
points.reserve( count ); points.reserve( count );
@ -129,32 +139,20 @@ namespace
addDataPoints( points, Diagram::Area ); addDataPoints( points, Diagram::Area );
} }
};
}
UsageDiagramLegend::UsageDiagramLegend( QQuickItem* parent ) UsageDiagramBox::UsageDiagramBox(const QString &title, Diagram *diagram, QQuickItem* parent )
: QskLinearBox( parent ) : Box( title, parent )
{ {
initSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed ); diagram->setParent( this );
diagram->setParentItem( this );
setMargins( 10, 10, 20, 10 );
setSpacing( 30 );
addItem( new LegendItem( UsageDiagramLegend::Water ) );
addItem( new LegendItem( UsageDiagramLegend::Electricity ) );
addItem( new LegendItem( UsageDiagramLegend::Gas ) );
}
UsageDiagramBox::UsageDiagramBox( QQuickItem* parent )
: Box( QString(), parent )
{
setSubcontrolProxy( QskBox::Panel, Panel ); setSubcontrolProxy( QskBox::Panel, Panel );
auto gridBox = new QskGridBox(); auto gridBox = new QskGridBox();
gridBox->setSpacing( 0 ); gridBox->setSpacing( 0 );
gridBox->addItem( new UsageDiagramLegend(), 0, 0, 1, -1, Qt::AlignTop | Qt::AlignRight ); gridBox->addItem( new UsageDiagramLegend(), 0, 0, 1, -1, Qt::AlignTop | Qt::AlignRight );
gridBox->addItem( new UsageDiagram(), 0, 0, 1, -1 ); gridBox->addItem( diagram, 0, 0, 1, -1 );
const char* days[] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" }; const char* days[] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };

View File

@ -6,6 +6,7 @@
#pragma once #pragma once
#include "Box.h" #include "Box.h"
#include "Diagram.h"
class UsageDiagramLegend : public QskLinearBox class UsageDiagramLegend : public QskLinearBox
{ {
@ -16,6 +17,15 @@ class UsageDiagramLegend : public QskLinearBox
UsageDiagramLegend( QQuickItem* parent = nullptr ); UsageDiagramLegend( QQuickItem* parent = nullptr );
}; };
class UsageDiagram : public Diagram
{
public:
UsageDiagram( QQuickItem* parent = nullptr );
private:
void addCurve( const qreal values[], const size_t count );
};
class UsageDiagramBox : public Box class UsageDiagramBox : public Box
{ {
Q_OBJECT Q_OBJECT
@ -23,5 +33,5 @@ class UsageDiagramBox : public Box
public: public:
QSK_SUBCONTROLS( Panel, DaysBox, DayText ) QSK_SUBCONTROLS( Panel, DaysBox, DayText )
UsageDiagramBox( QQuickItem* parent = nullptr ); UsageDiagramBox( const QString& title, Diagram* diagram, QQuickItem* parent = nullptr );
}; };