IOT dashboard: Make light dimmer use arc renderer
This commit is contained in:
parent
411e9832fd
commit
1b90e27b72
|
@ -0,0 +1,34 @@
|
|||
/******************************************************************************
|
||||
* Copyright (C) 2021 Edelhirsch Software GmbH
|
||||
* This file may be used under the terms of the 3-clause BSD License
|
||||
*****************************************************************************/
|
||||
|
||||
#include "LightDisplay.h"
|
||||
#include "Skin.h"
|
||||
|
||||
#include <QskAnimator.h>
|
||||
#include <QskRgbValue.h>
|
||||
#include <QskSetup.h>
|
||||
#include <QskTextLabel.h>
|
||||
#include <QskQuick.h>
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QQuickWindow>
|
||||
#include <QQuickPaintedItem>
|
||||
#include <QPainter>
|
||||
#include <QRadialGradient>
|
||||
|
||||
QSK_SUBCONTROL( LightDisplay, Groove )
|
||||
QSK_SUBCONTROL( LightDisplay, ColdPart )
|
||||
QSK_SUBCONTROL( LightDisplay, WarmPart )
|
||||
QSK_SUBCONTROL( LightDisplay, ValueText )
|
||||
QSK_SUBCONTROL( LightDisplay, LeftLabel )
|
||||
QSK_SUBCONTROL( LightDisplay, RightLabel )
|
||||
|
||||
LightDisplay::LightDisplay( QQuickItem* parent )
|
||||
: QskBoundedControl( parent )
|
||||
{
|
||||
setAlignmentHint( LeftLabel, Qt::AlignRight );
|
||||
}
|
||||
|
||||
#include "moc_LightDisplay.cpp"
|
|
@ -5,22 +5,14 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <QskLinearBox.h>
|
||||
#include <QskBoundedControl.h>
|
||||
|
||||
class QskTextLabel;
|
||||
|
||||
class LightDisplay : public QskLinearBox
|
||||
class LightDisplay : public QskBoundedControl
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QSK_SUBCONTROLS( Panel, ColdPart, WarmPart, ValueText )
|
||||
QSK_SUBCONTROLS( Groove, ColdPart, WarmPart, ValueText, LeftLabel, RightLabel )
|
||||
|
||||
LightDisplay( QQuickItem* parent = nullptr );
|
||||
|
||||
protected:
|
||||
void updateLayout() override;
|
||||
|
||||
private:
|
||||
QskTextLabel* m_valueLabel;
|
||||
};
|
|
@ -0,0 +1,124 @@
|
|||
/******************************************************************************
|
||||
* Copyright (C) 2021 Edelhirsch Software GmbH
|
||||
* This file may be used under the terms of the 3-clause BSD License
|
||||
*****************************************************************************/
|
||||
|
||||
#include "LightDisplaySkinlet.h"
|
||||
#include "LightDisplay.h"
|
||||
|
||||
#include <QskTextOptions.h>
|
||||
|
||||
#include <QFontMetrics>
|
||||
|
||||
LightDisplaySkinlet::LightDisplaySkinlet( QskSkin* skin )
|
||||
: QskSkinlet( skin )
|
||||
{
|
||||
setNodeRoles( { GrooveRole, WarmPartRole, ColdPartRole, ValueTextRole,
|
||||
LeftLabelRole, RightLabelRole } );
|
||||
}
|
||||
|
||||
LightDisplaySkinlet::~LightDisplaySkinlet()
|
||||
{
|
||||
}
|
||||
|
||||
QRectF LightDisplaySkinlet::subControlRect( const QskSkinnable* skinnable,
|
||||
const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const
|
||||
{
|
||||
auto* display = static_cast< const LightDisplay* >( skinnable );
|
||||
QRectF rect = contentsRect;
|
||||
|
||||
if( subControl == LightDisplay::Groove )
|
||||
{
|
||||
QSizeF size = textLabelsSize( display );
|
||||
|
||||
const qreal x = size.width();
|
||||
const qreal w = contentsRect.width() - 2 * size.width();
|
||||
const qreal y = 0;
|
||||
const qreal h = contentsRect.height();
|
||||
|
||||
const qreal diameter = qMin( w, h );
|
||||
|
||||
rect = QRectF( x, y, diameter, diameter );
|
||||
return rect;
|
||||
}
|
||||
else if( subControl == LightDisplay::LeftLabel )
|
||||
{
|
||||
QRectF grooveRect = subControlRect( skinnable, contentsRect, LightDisplay::Groove );
|
||||
QSizeF size = textLabelsSize( display );
|
||||
|
||||
rect.setWidth( size.width() );
|
||||
|
||||
rect.setY( grooveRect.y() + ( grooveRect.height() - size.height() ) / 2 );
|
||||
rect.setHeight( size.height() );
|
||||
|
||||
return rect;
|
||||
}
|
||||
else if( subControl == LightDisplay::RightLabel )
|
||||
{
|
||||
QRectF grooveRect = subControlRect( skinnable, contentsRect, LightDisplay::Groove );
|
||||
QSizeF size = textLabelsSize( display );
|
||||
|
||||
rect.setX( rect.right() - size.width() );
|
||||
|
||||
rect.setY( grooveRect.y() + ( grooveRect.height() - size.height() ) / 2 );
|
||||
rect.setHeight( size.height() );
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
return contentsRect;
|
||||
}
|
||||
|
||||
QSGNode* LightDisplaySkinlet::updateSubNode(
|
||||
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const
|
||||
{
|
||||
switch( nodeRole )
|
||||
{
|
||||
case GrooveRole:
|
||||
{
|
||||
return updateArcNode( skinnable, node, 0, 5760,
|
||||
LightDisplay::Groove );
|
||||
}
|
||||
case WarmPartRole:
|
||||
{
|
||||
// const qreal startAngle = 90 * 16;
|
||||
// const auto bar = static_cast< const LightDisplay* >( skinnable );
|
||||
// const qreal spanAngle = bar->valueAsRatio() * -5760;
|
||||
// return updateArcNode( skinnable, node, startAngle, spanAngle,
|
||||
// LightDisplay::Bar );
|
||||
}
|
||||
case ColdPartRole:
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
case ValueTextRole:
|
||||
{
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
case LeftLabelRole:
|
||||
{
|
||||
return updateTextNode( skinnable, node, QStringLiteral( "0" ), {},
|
||||
LightDisplay::LeftLabel );
|
||||
}
|
||||
case RightLabelRole:
|
||||
{
|
||||
return updateTextNode( skinnable, node, QStringLiteral( "100" ), {},
|
||||
LightDisplay::RightLabel );
|
||||
}
|
||||
}
|
||||
|
||||
return Inherited::updateSubNode( skinnable, nodeRole, node );
|
||||
}
|
||||
|
||||
QSizeF LightDisplaySkinlet::textLabelsSize( const LightDisplay* display ) const
|
||||
{
|
||||
QFont font = display->effectiveFont( LightDisplay::LeftLabel );
|
||||
QFontMetricsF fm( font );
|
||||
|
||||
qreal w = fm.width( QStringLiteral( "100" ) );
|
||||
qreal h = fm.height();
|
||||
return { w, h };
|
||||
}
|
||||
|
||||
#include "moc_LightDisplaySkinlet.cpp"
|
|
@ -0,0 +1,43 @@
|
|||
/******************************************************************************
|
||||
* 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 LightDisplay;
|
||||
|
||||
class LightDisplaySkinlet : public QskSkinlet
|
||||
{
|
||||
Q_GADGET
|
||||
|
||||
using Inherited = QskSkinlet;
|
||||
|
||||
public:
|
||||
enum NodeRole
|
||||
{
|
||||
GrooveRole,
|
||||
ColdPartRole,
|
||||
WarmPartRole,
|
||||
ValueTextRole,
|
||||
LeftLabelRole,
|
||||
RightLabelRole,
|
||||
|
||||
RoleCount,
|
||||
};
|
||||
|
||||
Q_INVOKABLE LightDisplaySkinlet( QskSkin* = nullptr );
|
||||
~LightDisplaySkinlet() override;
|
||||
|
||||
QRectF subControlRect( const QskSkinnable*,
|
||||
const QRectF&, QskAspect::Subcontrol ) const override;
|
||||
|
||||
protected:
|
||||
QSGNode* updateSubNode( const QskSkinnable*,
|
||||
quint8 nodeRole, QSGNode* ) const override;
|
||||
|
||||
private:
|
||||
QSizeF textLabelsSize( const LightDisplay* display ) const;
|
||||
};
|
|
@ -1,248 +0,0 @@
|
|||
/******************************************************************************
|
||||
* Copyright (C) 2021 Edelhirsch Software GmbH
|
||||
* This file may be used under the terms of the 3-clause BSD License
|
||||
*****************************************************************************/
|
||||
|
||||
#include "LightIntensity.h"
|
||||
#include "Skin.h"
|
||||
|
||||
#include <QskAnimator.h>
|
||||
#include <QskRgbValue.h>
|
||||
#include <QskSetup.h>
|
||||
#include <QskTextLabel.h>
|
||||
#include <QskQuick.h>
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QQuickWindow>
|
||||
#include <QQuickPaintedItem>
|
||||
#include <QPainter>
|
||||
#include <QRadialGradient>
|
||||
|
||||
QSK_SUBCONTROL( LightDisplay, Panel )
|
||||
QSK_SUBCONTROL( LightDisplay, ColdPart )
|
||||
QSK_SUBCONTROL( LightDisplay, WarmPart )
|
||||
QSK_SUBCONTROL( LightDisplay, ValueText )
|
||||
|
||||
namespace
|
||||
{
|
||||
class LightDimmer;
|
||||
|
||||
QColor invertedColor( const QColor& c )
|
||||
{
|
||||
QColor ret = { 255 - c.red(), 255 - c.green(), 255 - c.blue()};
|
||||
return ret;
|
||||
}
|
||||
|
||||
class LightDimmer : public QQuickPaintedItem
|
||||
{
|
||||
public:
|
||||
LightDimmer( const QskGradient& coldGradient,
|
||||
const QskGradient& warmGradient, QQuickItem* parent );
|
||||
|
||||
double thickness() const
|
||||
{
|
||||
return m_thickness;
|
||||
}
|
||||
|
||||
void setThickness( double thickness )
|
||||
{
|
||||
m_thickness = thickness;
|
||||
}
|
||||
|
||||
QColor backgroundColor() const
|
||||
{
|
||||
return m_backgroundColor;
|
||||
}
|
||||
|
||||
void setBackgroundColor( const QColor& color )
|
||||
{
|
||||
m_backgroundColor = color;
|
||||
}
|
||||
|
||||
QRadialGradient ringGradient() const
|
||||
{
|
||||
return m_ringGradient;
|
||||
}
|
||||
|
||||
void setRingGradient( const QRadialGradient& gradient )
|
||||
{
|
||||
m_ringGradient = gradient;
|
||||
}
|
||||
|
||||
QRectF ringRect() const
|
||||
{
|
||||
const qreal r = qMin( width(), height() ) - 4;
|
||||
return QRectF( 0.0, 0.0, r, r );
|
||||
}
|
||||
|
||||
private:
|
||||
void paint( QPainter* ) override;
|
||||
void updateGradient();
|
||||
|
||||
double m_thickness = 17.57;
|
||||
QColor m_backgroundColor;
|
||||
QRadialGradient m_ringGradient;
|
||||
QskGradient m_coldGradient;
|
||||
QskGradient m_warmGradient;
|
||||
};
|
||||
|
||||
// ### There must be an easier way to do this
|
||||
class DimmerAnimator : public QskAnimator
|
||||
{
|
||||
public:
|
||||
DimmerAnimator( LightDisplay* display, LightDimmer* dimmer )
|
||||
: m_display( display )
|
||||
, m_dimmer( dimmer )
|
||||
{
|
||||
QQuickWindow* w = static_cast< QQuickWindow* >( qGuiApp->allWindows().at( 0 ) );
|
||||
setWindow( w );
|
||||
setDuration( 500 );
|
||||
setEasingCurve( QEasingCurve::Linear );
|
||||
}
|
||||
|
||||
void setup() override
|
||||
{
|
||||
m_backgroundColor = m_display->color( LightDisplay::Panel );
|
||||
m_ringGradient = m_dimmer->ringGradient();
|
||||
}
|
||||
|
||||
void advance( qreal value ) override
|
||||
{
|
||||
const QColor c = m_backgroundColor;
|
||||
const QColor c2 = invertedColor( c );
|
||||
const QColor newColor = QskRgb::interpolated( c2, c, value );
|
||||
m_dimmer->setBackgroundColor( newColor );
|
||||
|
||||
QRadialGradient gradient = m_ringGradient;
|
||||
QRadialGradient newGradient = gradient;
|
||||
|
||||
for( const QGradientStop& stop : gradient.stops() )
|
||||
{
|
||||
QColor c = stop.second;
|
||||
QColor c2 = invertedColor( c );
|
||||
const QColor newColor = QskRgb::interpolated( c, c2, value );
|
||||
newGradient.setColorAt( stop.first, newColor );
|
||||
}
|
||||
|
||||
m_dimmer->setRingGradient( newGradient );
|
||||
m_dimmer->update();
|
||||
}
|
||||
|
||||
private:
|
||||
QColor m_backgroundColor;
|
||||
QRadialGradient m_ringGradient;
|
||||
LightDisplay* m_display;
|
||||
LightDimmer* m_dimmer;
|
||||
};
|
||||
}
|
||||
|
||||
LightDimmer::LightDimmer( const QskGradient& coldGradient,
|
||||
const QskGradient& warmGradient, QQuickItem* parent )
|
||||
: QQuickPaintedItem( parent )
|
||||
, m_coldGradient( coldGradient )
|
||||
, m_warmGradient( warmGradient )
|
||||
{
|
||||
connect( this, &QQuickPaintedItem::widthChanged,
|
||||
this, &LightDimmer::updateGradient );
|
||||
|
||||
connect( this, &QQuickPaintedItem::heightChanged,
|
||||
this, &LightDimmer::updateGradient );
|
||||
}
|
||||
|
||||
void LightDimmer::updateGradient()
|
||||
{
|
||||
const auto sz = ringRect().size();
|
||||
|
||||
QRadialGradient ringGradient( sz.width() / 2, sz.height() / 2, 110 );
|
||||
QGradientStop stop1( 0.0, "#c0c0c0" );
|
||||
QGradientStop stop2( 0.5, "#f0f0f0" );
|
||||
QGradientStop stop3( 1.0, "#c0c0c0" );
|
||||
ringGradient.setStops( {stop1, stop2, stop3} );
|
||||
|
||||
m_ringGradient = ringGradient;
|
||||
}
|
||||
|
||||
void LightDimmer::paint( QPainter* painter )
|
||||
{
|
||||
const auto sz = ringRect().size();
|
||||
|
||||
const qreal knobDiameter = 15.65;
|
||||
const qreal offset = ( thickness() - knobDiameter ) + 2;
|
||||
|
||||
painter->setRenderHint( QPainter::Antialiasing, true );
|
||||
|
||||
QRectF outerRect( 0, offset, sz.width(), sz.height() );
|
||||
|
||||
painter->setBrush( m_ringGradient );
|
||||
|
||||
painter->setPen( m_backgroundColor );
|
||||
painter->drawEllipse( outerRect );
|
||||
|
||||
int startAngle = 16 * 180;
|
||||
int middleAngle = 16 * -90;
|
||||
int endAngle = 16 * -90;
|
||||
|
||||
QLinearGradient coldGradient( {thickness(), 0.0}, {thickness(), thickness()} );
|
||||
coldGradient.setColorAt( 0, m_coldGradient.colorAt( 0 ) );
|
||||
coldGradient.setColorAt( 1, m_coldGradient.colorAt( 1 ) );
|
||||
painter->setBrush( coldGradient );
|
||||
painter->setPen( Qt::transparent );
|
||||
painter->drawPie( outerRect, startAngle, middleAngle );
|
||||
|
||||
QLinearGradient warmGradient( {thickness(), 0.0}, {thickness(), thickness()} );
|
||||
warmGradient.setColorAt( 0, m_warmGradient.colorAt( 0 ) );
|
||||
warmGradient.setColorAt( 1, m_warmGradient.colorAt( 1 ) );
|
||||
painter->setBrush( warmGradient );
|
||||
painter->drawPie( outerRect, 16 * 90, endAngle );
|
||||
|
||||
painter->setBrush( m_backgroundColor );
|
||||
painter->setPen( m_backgroundColor );
|
||||
QRectF innerRect( thickness() / 2, thickness() / 2 + offset, sz.width() - thickness(), sz.height() - thickness() );
|
||||
painter->drawEllipse( innerRect );
|
||||
|
||||
painter->setBrush( m_backgroundColor );
|
||||
painter->setPen( "#c4c4c4" );
|
||||
QRectF knobRect( ( sz.width() - knobDiameter ) / 2, 1, knobDiameter, knobDiameter );
|
||||
painter->drawEllipse( knobRect );
|
||||
}
|
||||
|
||||
LightDisplay::LightDisplay( QQuickItem* parent )
|
||||
: QskLinearBox( Qt::Horizontal, parent )
|
||||
{
|
||||
setSubcontrolProxy( QskBox::Panel, LightDisplay::Panel );
|
||||
|
||||
auto leftLabel = new QskTextLabel( QString::number( 0 ), this );
|
||||
leftLabel->setSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed );
|
||||
|
||||
auto rightLabel = new QskTextLabel( QString::number( 100 ), this );
|
||||
rightLabel->setSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed );
|
||||
|
||||
auto dimmer = new LightDimmer( gradientHint( ColdPart ), gradientHint( WarmPart ), this );
|
||||
dimmer->setBackgroundColor( color( Panel ) );
|
||||
|
||||
m_valueLabel = new QskTextLabel( QString::number( 50 ) + "%", dimmer );
|
||||
m_valueLabel->setSubcontrolProxy( QskTextLabel::Text, LightDisplay::ValueText );
|
||||
|
||||
addItem( leftLabel );
|
||||
addItem( dimmer );
|
||||
addItem( rightLabel );
|
||||
|
||||
auto animator = new DimmerAnimator( this, dimmer );
|
||||
connect( qskSetup, &QskSetup::skinChanged,
|
||||
[animator]() { animator->start(); } );
|
||||
}
|
||||
|
||||
void LightDisplay::updateLayout()
|
||||
{
|
||||
QskLinearBox::updateLayout();
|
||||
|
||||
auto dimmer = static_cast< const LightDimmer* >( m_valueLabel->parentItem() );
|
||||
|
||||
QRectF r;
|
||||
r.setSize( m_valueLabel->sizeConstraint() );
|
||||
r.moveCenter( dimmer->ringRect().center() + QPointF( 0, 4 ) );
|
||||
|
||||
m_valueLabel->setGeometry( r );
|
||||
}
|
||||
|
||||
#include "moc_LightIntensity.cpp"
|
|
@ -8,7 +8,7 @@
|
|||
#include "Box.h"
|
||||
#include "BoxWithButtons.h"
|
||||
#include "UsageDiagram.h"
|
||||
#include "LightIntensity.h"
|
||||
#include "LightDisplay.h"
|
||||
#include "MyDevices.h"
|
||||
#include "PieChart.h"
|
||||
#include "TopBar.h"
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
#include "CircularProgressBarSkinlet.h"
|
||||
#include "Diagram.h"
|
||||
#include "DiagramSkinlet.h"
|
||||
#include "LightIntensity.h"
|
||||
#include "LightDisplay.h"
|
||||
#include "LightDisplaySkinlet.h"
|
||||
#include "MainContent.h"
|
||||
#include "MenuBar.h"
|
||||
#include "PieChartPainted.h"
|
||||
|
@ -54,6 +55,7 @@ Skin::Skin( const Palette& palette, QObject* parent )
|
|||
{
|
||||
declareSkinlet< CircularProgressBar, CircularProgressBarSkinlet >();
|
||||
declareSkinlet< Diagram, DiagramSkinlet >();
|
||||
declareSkinlet< LightDisplay, LightDisplaySkinlet >();
|
||||
|
||||
initHints( palette );
|
||||
}
|
||||
|
@ -180,6 +182,8 @@ void Skin::initHints( const Palette& palette )
|
|||
ed.setColor( Diagram::ChartArea3, "#66ff7d34" );
|
||||
|
||||
// light intensity:
|
||||
ed.setGradient( LightDisplay::Groove, Qt::magenta );
|
||||
ed.setArcMetrics( LightDisplay::Groove, { 10, 0, 5760 } );
|
||||
ed.setGradient( LightDisplay::ColdPart, { Qt::Horizontal, "#a7b0ff", "#6776ff" } );
|
||||
ed.setGradient( LightDisplay::WarmPart, { Qt::Horizontal, "#feeeb7", "#ff3122" } );
|
||||
ed.setFontRole( LightDisplay::ValueText, QskSkin::LargeFont );
|
||||
|
@ -191,7 +195,7 @@ void Skin::initHints( const Palette& palette )
|
|||
ed.setGradient( Box::Panel, palette.box );
|
||||
ed.setGradient( BoxWithButtons::Panel, palette.box );
|
||||
ed.setGradient( UsageDiagramBox::Panel, palette.box );
|
||||
ed.setColor( LightDisplay::Panel, palette.lightDisplay );
|
||||
// ed.setColor( LightDisplay::Panel, palette.lightDisplay ); ###
|
||||
ed.setGradient( RoundButton::Panel, palette.roundButton );
|
||||
ed.setBoxBorderColors( UsageDiagramBox::DaysBox, palette.weekdayBox );
|
||||
ed.setColor( QskTextLabel::Text, palette.text );
|
||||
|
|
|
@ -10,7 +10,8 @@ SOURCES += \
|
|||
Diagram.cpp \
|
||||
DiagramSkinlet.cpp \
|
||||
GraphicProvider.cpp \
|
||||
LightIntensity.cpp \
|
||||
LightDisplaySkinlet.cpp \
|
||||
LightDisplay.cpp \
|
||||
MainContent.cpp \
|
||||
MenuBar.cpp \
|
||||
MyDevices.cpp \
|
||||
|
@ -40,7 +41,8 @@ HEADERS += \
|
|||
Diagram.h \
|
||||
DiagramSkinlet.h \
|
||||
GraphicProvider.h \
|
||||
LightIntensity.h \
|
||||
LightDisplaySkinlet.h \
|
||||
LightDisplay.h \
|
||||
MainContent.h \
|
||||
MainWindow.h \
|
||||
MenuBar.h \
|
||||
|
|
Loading…
Reference in New Issue