2021-11-19 15:02:57 +01:00
|
|
|
/******************************************************************************
|
|
|
|
* 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 "nodes/RadialTickmarksNode.h"
|
|
|
|
|
|
|
|
#include <QskArcMetrics.h>
|
|
|
|
#include <QskTextOptions.h>
|
2022-03-23 15:39:17 +01:00
|
|
|
#include <QskScaleTickmarks.h>
|
2022-06-04 17:56:14 +02:00
|
|
|
#include <QskBoxShadowNode.h>
|
|
|
|
#include <QskSGNode.h>
|
2021-11-19 15:02:57 +01:00
|
|
|
|
|
|
|
#include <QFontMetrics>
|
|
|
|
#include <QtMath>
|
|
|
|
|
|
|
|
LightDisplaySkinlet::LightDisplaySkinlet( QskSkin* skin )
|
|
|
|
: QskSkinlet( skin )
|
|
|
|
{
|
|
|
|
setNodeRoles( { GrooveRole, PanelRole, ColdAndWarmArcRole, TickmarksRole,
|
|
|
|
ValueTextRole, LeftLabelRole, RightLabelRole, KnobRole } );
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
const qreal ticksSpacing = 4; // space between the ticks and the arc
|
|
|
|
|
2022-03-23 11:54:34 +01:00
|
|
|
if( subControl == LightDisplay::Groove || subControl == LightDisplay::Panel )
|
2021-11-19 15:02:57 +01:00
|
|
|
{
|
2022-10-26 17:02:06 +02:00
|
|
|
const auto textSize = textLabelsSize( display );
|
|
|
|
const auto arcMetrics = display->arcMetricsHint( LightDisplay::ColdAndWarmArc );
|
2021-11-19 15:02:57 +01:00
|
|
|
const qreal ticksWidth = display->arcMetricsHint( LightDisplay::Tickmarks ).width() + ticksSpacing;
|
|
|
|
|
|
|
|
const qreal x = textSize.width() + arcMetrics.width() + ticksWidth;
|
2022-03-23 11:54:34 +01:00
|
|
|
const qreal w = contentsRect.width() -
|
|
|
|
( 2 * ( textSize.width() + arcMetrics.width() + ticksWidth ) );
|
2021-11-19 15:02:57 +01:00
|
|
|
const qreal y = arcMetrics.width() + ticksWidth;
|
|
|
|
const qreal h = contentsRect.height() - 2 * ( arcMetrics.width() + ticksWidth );
|
|
|
|
|
|
|
|
const qreal diameter = qMin( w, h );
|
|
|
|
|
|
|
|
rect = QRectF( x, y, diameter, diameter );
|
|
|
|
return rect;
|
|
|
|
}
|
|
|
|
else if( subControl == LightDisplay::ColdAndWarmArc )
|
|
|
|
{
|
2022-03-23 11:54:34 +01:00
|
|
|
const QRectF panelRect = subControlRect( skinnable, contentsRect, LightDisplay::Panel );
|
2021-11-19 15:02:57 +01:00
|
|
|
auto barWidth = display->arcMetricsHint( LightDisplay::ColdAndWarmArc ).width();
|
|
|
|
auto rect = panelRect.marginsAdded( { barWidth, barWidth, barWidth, barWidth } );
|
|
|
|
return rect;
|
|
|
|
}
|
|
|
|
else if( subControl == LightDisplay::Tickmarks )
|
|
|
|
{
|
2022-03-23 11:54:34 +01:00
|
|
|
const QRectF arcRect = subControlRect(
|
|
|
|
skinnable, contentsRect, LightDisplay::ColdAndWarmArc );
|
|
|
|
const qreal ticksWidth = display->arcMetricsHint(
|
|
|
|
LightDisplay::Tickmarks ).width() + ticksSpacing;
|
|
|
|
const QRectF rect =
|
|
|
|
arcRect.marginsAdded( { ticksWidth, ticksWidth, ticksWidth, ticksWidth } );
|
2021-11-19 15:02:57 +01:00
|
|
|
return rect;
|
2021-11-22 15:51:40 +01:00
|
|
|
}
|
|
|
|
else if( subControl == LightDisplay::ValueText )
|
|
|
|
{
|
2022-03-23 11:54:34 +01:00
|
|
|
QRectF valueTextRect = subControlRect( skinnable, contentsRect, LightDisplay::Panel );
|
2021-11-22 15:51:40 +01:00
|
|
|
const QFontMetricsF fm( skinnable->effectiveFont( subControl ) );
|
2022-05-30 20:03:56 +02:00
|
|
|
const qreal fontWidth = qskHorizontalAdvance( fm, QStringLiteral( "100 %" ) );
|
2021-11-22 15:51:40 +01:00
|
|
|
const QPointF center = valueTextRect.center();
|
|
|
|
const QRectF rect( center.x() - fontWidth / 2, center.y() - fm.height() / 2, fontWidth, fm.height() );
|
|
|
|
return rect;
|
2021-11-19 15:02:57 +01:00
|
|
|
}
|
|
|
|
else if( subControl == LightDisplay::LeftLabel )
|
|
|
|
{
|
|
|
|
const QRectF ticksRect = subControlRect( skinnable, contentsRect, LightDisplay::Tickmarks );
|
2022-10-26 17:02:06 +02:00
|
|
|
const auto size = textLabelsSize( display );
|
2021-11-19 15:02:57 +01:00
|
|
|
|
|
|
|
rect.setWidth( size.width() );
|
|
|
|
|
|
|
|
rect.setY( ticksRect.y() + ( ticksRect.height() - size.height() ) / 2 );
|
|
|
|
rect.setHeight( size.height() );
|
|
|
|
|
|
|
|
return rect;
|
|
|
|
}
|
|
|
|
else if( subControl == LightDisplay::RightLabel )
|
|
|
|
{
|
2022-10-26 17:02:06 +02:00
|
|
|
const auto ticksRect = subControlRect( skinnable, contentsRect, LightDisplay::Tickmarks );
|
|
|
|
const auto size = textLabelsSize( display );
|
2021-11-19 15:02:57 +01:00
|
|
|
|
|
|
|
rect.setX( ticksRect.x() + ticksRect.width() );
|
|
|
|
|
|
|
|
rect.setY( ticksRect.y() + ( ticksRect.height() - size.height() ) / 2 );
|
|
|
|
rect.setHeight( size.height() );
|
|
|
|
|
|
|
|
return rect;
|
|
|
|
}
|
|
|
|
else if( subControl == LightDisplay::Knob )
|
|
|
|
{
|
2022-10-26 17:02:06 +02:00
|
|
|
const auto arcRect = subControlRect( skinnable, contentsRect, LightDisplay::ColdAndWarmArc );
|
|
|
|
const auto arcMetrics = display->arcMetricsHint( LightDisplay::ColdAndWarmArc );
|
|
|
|
const auto knobSize = display->strutSizeHint( LightDisplay::Knob );
|
2021-11-19 15:02:57 +01:00
|
|
|
|
|
|
|
const qreal radius = ( arcRect.width() - arcMetrics.width() ) / 2;
|
|
|
|
const qreal angle = display->valueAsRatio() * 180;
|
|
|
|
|
|
|
|
const qreal cos = qFastCos( qDegreesToRadians( angle ) );
|
|
|
|
const qreal sin = qFastSin( qDegreesToRadians( angle ) );
|
|
|
|
|
|
|
|
const auto x = arcRect.center().x() - knobSize.width() / 2 - radius * cos;
|
|
|
|
const auto y = arcRect.center().y() - knobSize.height() / 2 - radius * sin;
|
|
|
|
|
|
|
|
rect = QRectF( x, y, knobSize.width(), knobSize.height() );
|
|
|
|
return rect;
|
|
|
|
}
|
|
|
|
|
|
|
|
return contentsRect;
|
|
|
|
}
|
|
|
|
|
|
|
|
QSGNode* LightDisplaySkinlet::updateSubNode(
|
|
|
|
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const
|
|
|
|
{
|
2022-03-23 15:39:17 +01:00
|
|
|
const auto* display = static_cast< const LightDisplay* >( skinnable );
|
2021-11-19 15:02:57 +01:00
|
|
|
|
|
|
|
switch( nodeRole )
|
|
|
|
{
|
|
|
|
case PanelRole:
|
|
|
|
{
|
|
|
|
return updateBoxNode( skinnable, node, LightDisplay::Panel );
|
|
|
|
}
|
|
|
|
case GrooveRole:
|
|
|
|
{
|
|
|
|
const QRectF grooveRect = display->subControlRect( LightDisplay::Groove );
|
|
|
|
if ( grooveRect.isEmpty() )
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
const auto& shadowMetrics = display->shadow();
|
2022-06-15 10:59:39 +02:00
|
|
|
const auto shadowRect = shadowMetrics.shadowRect( grooveRect );
|
2021-11-19 15:02:57 +01:00
|
|
|
|
2022-06-15 10:59:39 +02:00
|
|
|
auto shadowNode = QskSGNode::ensureNode< QskBoxShadowNode >( node );
|
|
|
|
shadowNode->setShadowData( shadowRect, grooveRect.width() / 2,
|
|
|
|
shadowMetrics.blurRadius(), display->shadowColor() );
|
2021-11-19 15:02:57 +01:00
|
|
|
|
|
|
|
return shadowNode;
|
|
|
|
}
|
|
|
|
case ColdAndWarmArcRole:
|
|
|
|
{
|
|
|
|
return updateArcNode( skinnable, node, LightDisplay::ColdAndWarmArc );
|
|
|
|
}
|
|
|
|
case TickmarksRole:
|
|
|
|
{
|
|
|
|
auto ticksNode = static_cast< RadialTickmarksNode* >( node );
|
|
|
|
if ( ticksNode == nullptr )
|
|
|
|
ticksNode = new RadialTickmarksNode();
|
|
|
|
|
2022-03-23 15:39:17 +01:00
|
|
|
const auto color = display->color( LightDisplay::Tickmarks );
|
|
|
|
const auto ticksRect = display->subControlRect( LightDisplay::Tickmarks );
|
|
|
|
const auto arcMetrics = display->arcMetricsHint( LightDisplay::Tickmarks );
|
|
|
|
|
2021-11-19 15:02:57 +01:00
|
|
|
QskScaleTickmarks tickmarks;
|
2022-03-23 15:39:17 +01:00
|
|
|
tickmarks.setMajorTicks( { 0, 22.5, 45, 67.5, 90, 112.5, 135, 157.5, 180 } );
|
2021-11-19 15:02:57 +01:00
|
|
|
|
2022-03-23 15:39:17 +01:00
|
|
|
const auto tickLineWidth = display->metric( LightDisplay::Tickmarks );
|
|
|
|
|
|
|
|
ticksNode->update( color, ticksRect, arcMetrics, tickmarks, tickLineWidth );
|
2021-11-19 15:02:57 +01:00
|
|
|
|
|
|
|
return ticksNode;
|
|
|
|
}
|
|
|
|
case ValueTextRole:
|
|
|
|
{
|
|
|
|
const QString valueText = QString::number( display->value(), 'f', 0 )
|
|
|
|
+ QStringLiteral( " %" );
|
2022-08-25 09:39:33 +02:00
|
|
|
return updateTextNode( skinnable, node, valueText,
|
2021-11-19 15:02:57 +01:00
|
|
|
LightDisplay::ValueText );
|
|
|
|
}
|
|
|
|
case LeftLabelRole:
|
|
|
|
{
|
2022-08-25 09:39:33 +02:00
|
|
|
return updateTextNode( skinnable, node, QStringLiteral( "0 " ),
|
2021-11-19 15:02:57 +01:00
|
|
|
LightDisplay::LeftLabel );
|
|
|
|
}
|
|
|
|
case RightLabelRole:
|
|
|
|
{
|
2022-08-25 09:39:33 +02:00
|
|
|
return updateTextNode( skinnable, node, QStringLiteral( " 100" ),
|
2021-11-19 15:02:57 +01:00
|
|
|
LightDisplay::RightLabel );
|
|
|
|
}
|
|
|
|
case KnobRole:
|
|
|
|
{
|
|
|
|
return updateBoxNode( skinnable, node, LightDisplay::Knob );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Inherited::updateSubNode( skinnable, nodeRole, node );
|
|
|
|
}
|
|
|
|
|
|
|
|
QSizeF LightDisplaySkinlet::textLabelsSize( const LightDisplay* display ) const
|
|
|
|
{
|
2022-03-23 15:39:17 +01:00
|
|
|
const QFontMetricsF fm( display->effectiveFont( LightDisplay::LeftLabel ) );
|
2021-11-19 15:02:57 +01:00
|
|
|
|
2022-05-30 20:03:56 +02:00
|
|
|
qreal w = qskHorizontalAdvance( fm, QStringLiteral( " 100" ) );
|
2021-11-19 15:02:57 +01:00
|
|
|
qreal h = fm.height();
|
2022-03-23 15:39:17 +01:00
|
|
|
|
2021-11-19 15:02:57 +01:00
|
|
|
return { w, h };
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "moc_LightDisplaySkinlet.cpp"
|