Iot dashboard arc rendering (#134)
* add QskArcNode and QskArcRenderer * IOT example: Use QskArcNode instead of own arc node * move some functionality to the arc renderer * add QskArcMetrics * add methods to QskSkinlet * remove circular bar graph node We can now use updateArcNode() and don't need our own method. * support linear gradients in the arc renderer * clean up * incorporate Uwe's changes * add overloads for updateArcNode() when the angles are set dynamically The angles don't always come from the style, so we need overloads in QskSkinlet to set them dynamically.
This commit is contained in:
parent
15102be421
commit
b89621a3d4
@ -6,6 +6,7 @@
|
||||
#include "CircularProgressBar.h"
|
||||
|
||||
#include <QskAnimator.h>
|
||||
#include <QskArcMetrics.h>
|
||||
#include <QskFunctions.h>
|
||||
|
||||
QSK_SUBCONTROL( CircularProgressBar, Groove )
|
||||
@ -179,6 +180,7 @@ void CircularProgressBar::setValueInternal( qreal value )
|
||||
if ( !qskFuzzyCompare( value, m_data->value ) )
|
||||
{
|
||||
m_data->value = value;
|
||||
|
||||
Q_EMIT valueChanged( value );
|
||||
|
||||
update();
|
||||
|
@ -11,132 +11,6 @@
|
||||
#include <QEasingCurve>
|
||||
#include <QPainter>
|
||||
|
||||
namespace
|
||||
{
|
||||
class ArcNode : public QskPaintedNode
|
||||
{
|
||||
public:
|
||||
void setGradient( const QskGradient& gradient )
|
||||
{
|
||||
m_gradient = gradient;
|
||||
}
|
||||
|
||||
void setGradientType( QGradient::Type type )
|
||||
{
|
||||
m_gradientType = type;
|
||||
}
|
||||
|
||||
void setWidth( double width )
|
||||
{
|
||||
m_width = width;
|
||||
}
|
||||
|
||||
void setValue( double value )
|
||||
{
|
||||
m_value = value;
|
||||
}
|
||||
|
||||
void setOrigin( double origin )
|
||||
{
|
||||
m_origin = origin;
|
||||
}
|
||||
|
||||
void setMaximum( double maximum )
|
||||
{
|
||||
m_maximum = maximum;
|
||||
}
|
||||
|
||||
void setIndeterminate( bool isIndeterminate )
|
||||
{
|
||||
m_isIndeterminate = isIndeterminate;
|
||||
}
|
||||
|
||||
void setPosition( double position )
|
||||
{
|
||||
m_position = position;
|
||||
}
|
||||
|
||||
void paint( QPainter* painter, const QSizeF& size ) override
|
||||
{
|
||||
int startAngle;
|
||||
int spanAngle;
|
||||
|
||||
if( m_isIndeterminate )
|
||||
{
|
||||
static const QEasingCurve curve( QEasingCurve::Linear );
|
||||
|
||||
startAngle = -1 * m_position * 360;
|
||||
// the other option is to just set a fixed value for the
|
||||
// span angle (or do some advanced stuff with easing curves)
|
||||
spanAngle = qAbs( 0.5 - m_position ) * 360;
|
||||
}
|
||||
else
|
||||
{
|
||||
startAngle = 90 + -1 * ( m_origin / m_maximum ) * 360;
|
||||
spanAngle = -1 * ( m_value / m_maximum ) * 360;
|
||||
}
|
||||
|
||||
painter->setRenderHint( QPainter::Antialiasing, true );
|
||||
|
||||
const QRectF r( 0.5 * m_width, 0.5 * m_width,
|
||||
size.width() - m_width, size.height() - m_width );
|
||||
|
||||
QGradientStops stops;
|
||||
|
||||
for( const QskGradientStop& stop : m_gradient.stops() )
|
||||
{
|
||||
QGradientStop s( stop.position(), stop.color() );
|
||||
stops.append( s );
|
||||
}
|
||||
|
||||
if( m_gradientType == QGradient::RadialGradient )
|
||||
{
|
||||
QRadialGradient radialGradient( r.center(), qMin( r.width(), r.height() ) );
|
||||
radialGradient.setStops( stops );
|
||||
|
||||
painter->setPen( QPen( radialGradient, m_width, Qt::SolidLine, Qt::FlatCap ) );
|
||||
painter->drawArc( r, startAngle * 16, spanAngle * 16 );
|
||||
}
|
||||
else
|
||||
{
|
||||
QConicalGradient conicalGradient( r.center(), startAngle );
|
||||
conicalGradient.setStops( stops );
|
||||
|
||||
painter->setPen( QPen( conicalGradient, m_width, Qt::SolidLine, Qt::FlatCap ) );
|
||||
painter->drawArc( r, startAngle * 16, spanAngle * 16 );
|
||||
}
|
||||
}
|
||||
|
||||
uint hash() const override
|
||||
{
|
||||
uint h = qHash( m_gradientType );
|
||||
h = qHash( m_width, h );
|
||||
h = qHash( m_value, h );
|
||||
h = qHash( m_origin, h );
|
||||
h = qHash( m_maximum, h );
|
||||
h = qHash( m_isIndeterminate, h );
|
||||
h = qHash( m_position, h );
|
||||
|
||||
for( const QskGradientStop& stop : m_gradient.stops() )
|
||||
{
|
||||
h = stop.hash( h );
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
private:
|
||||
QskGradient m_gradient;
|
||||
QGradient::Type m_gradientType;
|
||||
double m_width;
|
||||
double m_value;
|
||||
double m_origin;
|
||||
double m_maximum;
|
||||
bool m_isIndeterminate;
|
||||
double m_position;
|
||||
};
|
||||
}
|
||||
|
||||
CircularProgressBarSkinlet::CircularProgressBarSkinlet( QskSkin* skin )
|
||||
: QskSkinlet( skin )
|
||||
{
|
||||
@ -156,63 +30,23 @@ QRectF CircularProgressBarSkinlet::subControlRect(
|
||||
QSGNode* CircularProgressBarSkinlet::updateSubNode(
|
||||
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const
|
||||
{
|
||||
const auto bar = static_cast< const CircularProgressBar* >( skinnable );
|
||||
|
||||
switch( nodeRole )
|
||||
{
|
||||
case GrooveRole: // fall through
|
||||
case GrooveRole:
|
||||
{
|
||||
return updateArcNode( skinnable, node, CircularProgressBar::Groove );
|
||||
}
|
||||
case BarRole:
|
||||
{
|
||||
return updateBarNode( bar, nodeRole, node );
|
||||
const qreal startAngle = 90 * 16;
|
||||
const auto bar = static_cast< const CircularProgressBar* >( skinnable );
|
||||
const qreal spanAngle = bar->valueAsRatio() * -5760;
|
||||
return updateArcNode( skinnable, node, startAngle, spanAngle,
|
||||
CircularProgressBar::Bar );
|
||||
}
|
||||
}
|
||||
|
||||
return Inherited::updateSubNode( skinnable, nodeRole, node );
|
||||
}
|
||||
|
||||
QSGNode* CircularProgressBarSkinlet::updateBarNode(
|
||||
const CircularProgressBar* bar, quint8 nodeRole, QSGNode* node ) const
|
||||
{
|
||||
auto arcNode = static_cast< ArcNode* >( node );
|
||||
|
||||
if( arcNode == nullptr )
|
||||
{
|
||||
arcNode = new ArcNode();
|
||||
}
|
||||
|
||||
const auto subControl = ( nodeRole == GrooveRole ) ? CircularProgressBar::Groove
|
||||
: CircularProgressBar::Bar;
|
||||
|
||||
const QskGradient gradient = bar->gradientHint( subControl );
|
||||
|
||||
const QGradient::Type type = ( nodeRole == GrooveRole ) ?
|
||||
QGradient::RadialGradient : QGradient::ConicalGradient;
|
||||
|
||||
const double width = bar->metric( subControl | QskAspect::Size );
|
||||
const double value = ( nodeRole == GrooveRole ) ? bar->maximum() : bar->value();
|
||||
|
||||
arcNode->setGradient( gradient );
|
||||
arcNode->setGradientType( type );
|
||||
arcNode->setWidth( width );
|
||||
arcNode->setOrigin( bar->origin() );
|
||||
arcNode->setMaximum( bar->maximum() );
|
||||
arcNode->setIndeterminate( bar->isIndeterminate() );
|
||||
|
||||
if( bar->isIndeterminate() )
|
||||
{
|
||||
const double position = bar->metric( CircularProgressBar::Bar | QskAspect::Position );
|
||||
arcNode->setPosition( position );
|
||||
}
|
||||
else
|
||||
{
|
||||
arcNode->setValue( value );
|
||||
}
|
||||
|
||||
QQuickWindow* window = bar->window();
|
||||
const QRect rect = bar->contentsRect().toRect();
|
||||
arcNode->update( window, QskTextureRenderer::AutoDetect, rect );
|
||||
|
||||
return arcNode;
|
||||
}
|
||||
|
||||
#include "moc_CircularProgressBarSkinlet.cpp"
|
||||
|
@ -33,7 +33,4 @@ class CircularProgressBarSkinlet : public QskSkinlet
|
||||
protected:
|
||||
QSGNode* updateSubNode( const QskSkinnable*,
|
||||
quint8 nodeRole, QSGNode* ) const override;
|
||||
|
||||
private:
|
||||
QSGNode* updateBarNode( const CircularProgressBar*, quint8 nodeRole, QSGNode* ) const;
|
||||
};
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "UsageBox.h"
|
||||
#include "UsageDiagram.h"
|
||||
|
||||
#include <QskArcMetrics.h>
|
||||
#include <QskBoxShapeMetrics.h>
|
||||
#include <QskBoxBorderMetrics.h>
|
||||
#include <QskBoxBorderColors.h>
|
||||
@ -108,14 +109,16 @@ void Skin::initHints( const Palette& palette )
|
||||
ed.setColor( TopBarItem::Item4 | QskAspect::TextColor, "#6776ff" );
|
||||
|
||||
// conical gradients are counterclockwise, so specify the 2nd color first:
|
||||
ed.setGradient( TopBarItem::Item1, { Qt::Horizontal, "#FF3122", "#FF5C00" } );
|
||||
ed.setGradient( TopBarItem::Item2, { Qt::Horizontal, "#6100FF", "#6776FF" } );
|
||||
ed.setGradient( TopBarItem::Item3, { Qt::Horizontal, "#FF3122", "#FFCE50" } );
|
||||
ed.setGradient( TopBarItem::Item4, { Qt::Horizontal, "#6100FF", "#6776FF" } );
|
||||
ed.setGradient( TopBarItem::Item1, { QskGradient::Horizontal, "#FF3122", "#FF5C00" } );
|
||||
ed.setGradient( TopBarItem::Item2, { QskGradient::Horizontal, "#6100FF", "#6776FF" } );
|
||||
ed.setGradient( TopBarItem::Item3, { QskGradient::Horizontal, "#FF3122", "#FFCE50" } );
|
||||
ed.setGradient( TopBarItem::Item4, { QskGradient::Horizontal, "#6100FF", "#6776FF" } );
|
||||
|
||||
// the bar gradient is defined through the top bar items above
|
||||
ed.setMetricHint( CircularProgressBar::Groove | QskAspect::Size, 8.53 );
|
||||
ed.setMetricHint( CircularProgressBar::Bar | QskAspect::Size, 8.53 );
|
||||
ed.setArcMetrics( CircularProgressBar::Groove, { 8.53, 90 * 16, -360 * 16 } );
|
||||
// the span angle will be set in the progress bar, we just give a dummy
|
||||
// value here:
|
||||
ed.setArcMetrics( CircularProgressBar::Bar, { 8.53, 90 * 16, -180 * 16 } );
|
||||
|
||||
ed.setFontRole( TimeTitleLabel::Text, Skin::TitleFont );
|
||||
|
||||
|
@ -60,7 +60,7 @@ class DaytimeSkin : public Skin
|
||||
: Skin(
|
||||
Skin::Palette( {"#6D7BFB"}, {"#fbfbfb"}, {"#ffffff"},
|
||||
"#ffffff", {"#f7f7f7"}, {"#f4f4f4"}, Qt::black, Qt::black,
|
||||
{ Qt::Horizontal, { { 0.0, 0xc4c4c4 }, { 0.5, 0xf8f8f8 }, { 1.0, 0xc4c4c4 } } } )
|
||||
{ QskGradient::Vertical, { { 0.0, 0xc4c4c4 }, { 0.5, 0xf8f8f8 }, { 1.0, 0xc4c4c4 } } } )
|
||||
, parent )
|
||||
{
|
||||
}
|
||||
@ -73,7 +73,7 @@ class NighttimeSkin : public Skin
|
||||
: Skin(
|
||||
Skin::Palette( {"#2937A7"}, {"#040404"}, {"#000000"},
|
||||
"#000000", {"#0a0a0a"}, {"#0c0c0c"}, Qt::white, Qt::white,
|
||||
{ Qt::Horizontal, { { 0.0, 0x666666 }, { 0.5, 0x222222 }, { 1.0, 0x333333 } } } )
|
||||
{ QskGradient::Vertical, { { 0.0, 0x666666 }, { 0.5, 0x222222 }, { 1.0, 0x333333 } } } )
|
||||
, parent )
|
||||
{
|
||||
}
|
||||
|
123
src/common/QskArcMetrics.cpp
Normal file
123
src/common/QskArcMetrics.cpp
Normal file
@ -0,0 +1,123 @@
|
||||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2021 Uwe Rathmann
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "QskArcMetrics.h"
|
||||
|
||||
#include <qhashfunctions.h>
|
||||
#include <qvariant.h>
|
||||
|
||||
static void qskRegisterArcMetrics()
|
||||
{
|
||||
qRegisterMetaType< QskArcMetrics >();
|
||||
}
|
||||
|
||||
Q_CONSTRUCTOR_FUNCTION( qskRegisterArcMetrics )
|
||||
|
||||
// copied from QskMargins.cpp, we should unify this somehwere:
|
||||
static inline qreal qskInterpolated( qreal from, qreal to, qreal ratio )
|
||||
{
|
||||
return from + ( to - from ) * ratio;
|
||||
}
|
||||
|
||||
// copied from QskBoxBorderMetrics.cpp, we should unify this somewhere:
|
||||
static inline qreal qskAbsoluted( qreal length, qreal percentage )
|
||||
{
|
||||
// 100% means -> 0.5 of length
|
||||
percentage = qBound( 0.0, percentage, 100.0 );
|
||||
return percentage / 100.0 * 0.5 * length;
|
||||
}
|
||||
|
||||
void QskArcMetrics::setWidth( qreal width ) noexcept
|
||||
{
|
||||
m_width = width;
|
||||
}
|
||||
|
||||
void QskArcMetrics::setStartAngle( int startAngle ) noexcept
|
||||
{
|
||||
m_startAngle = startAngle;
|
||||
}
|
||||
|
||||
void QskArcMetrics::setSpanAngle( int spanAngle ) noexcept
|
||||
{
|
||||
m_spanAngle = spanAngle;
|
||||
}
|
||||
|
||||
void QskArcMetrics::setSizeMode( Qt::SizeMode sizeMode ) noexcept
|
||||
{
|
||||
m_sizeMode = sizeMode;
|
||||
}
|
||||
|
||||
QskArcMetrics QskArcMetrics::interpolated(
|
||||
const QskArcMetrics& to, qreal ratio ) const noexcept
|
||||
{
|
||||
if ( ( *this == to ) || ( m_sizeMode != to.m_sizeMode ) )
|
||||
return to;
|
||||
|
||||
const qreal width = qskInterpolated( m_width, to.m_width, ratio );
|
||||
return QskArcMetrics( width, m_startAngle, m_spanAngle, m_sizeMode );
|
||||
}
|
||||
|
||||
QVariant QskArcMetrics::interpolate(
|
||||
const QskArcMetrics& from, const QskArcMetrics& to,
|
||||
qreal progress )
|
||||
{
|
||||
return QVariant::fromValue( from.interpolated( to, progress ) );
|
||||
}
|
||||
|
||||
QskArcMetrics QskArcMetrics::toAbsolute( const QSizeF& size ) const noexcept
|
||||
{
|
||||
if ( m_sizeMode != Qt::RelativeSize )
|
||||
return *this;
|
||||
|
||||
QskArcMetrics absoluted = *this;
|
||||
|
||||
auto& w = absoluted.m_width;
|
||||
|
||||
if ( size.isEmpty() )
|
||||
{
|
||||
w = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// for now we just use the width:
|
||||
w = qskAbsoluted( size.width(), w );
|
||||
}
|
||||
|
||||
absoluted.m_sizeMode = Qt::AbsoluteSize;
|
||||
|
||||
return absoluted;
|
||||
}
|
||||
|
||||
uint QskArcMetrics::hash( uint seed ) const noexcept
|
||||
{
|
||||
uint hash = qHash( m_width, seed );
|
||||
hash = qHash( m_startAngle, hash );
|
||||
hash = qHash( m_spanAngle, hash );
|
||||
const int mode = m_sizeMode;
|
||||
return qHashBits( &mode, sizeof( mode ), hash );
|
||||
}
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
|
||||
#include <qdebug.h>
|
||||
|
||||
QDebug operator<<( QDebug debug, const QskArcMetrics& metrics )
|
||||
{
|
||||
QDebugStateSaver saver( debug );
|
||||
debug.nospace();
|
||||
|
||||
debug << "Arc" << '(';
|
||||
debug << "width:" << metrics.width();
|
||||
debug << ", start angle:" << metrics.startAngle();
|
||||
debug << ", span angle:" << metrics.spanAngle();
|
||||
debug << ", size mode:" << metrics.sizeMode();
|
||||
debug << ')';
|
||||
|
||||
return debug;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#include "moc_QskArcMetrics.cpp"
|
135
src/common/QskArcMetrics.h
Normal file
135
src/common/QskArcMetrics.h
Normal file
@ -0,0 +1,135 @@
|
||||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2021 Uwe Rathmann
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QSK_ARC_METRICS_H
|
||||
#define QSK_ARC_METRICS_H
|
||||
|
||||
#include "QskFunctions.h"
|
||||
|
||||
#include <qmetatype.h>
|
||||
|
||||
class QVariant;
|
||||
|
||||
class QSK_EXPORT QskArcMetrics
|
||||
{
|
||||
Q_GADGET
|
||||
|
||||
Q_PROPERTY( qreal width READ width WRITE setWidth )
|
||||
Q_PROPERTY( int startAngle READ startAngle WRITE setStartAngle )
|
||||
Q_PROPERTY( int spanAngle READ spanAngle WRITE setSpanAngle )
|
||||
Q_PROPERTY( Qt::SizeMode sizeMode READ sizeMode WRITE setSizeMode )
|
||||
|
||||
public:
|
||||
constexpr QskArcMetrics() noexcept;
|
||||
|
||||
constexpr QskArcMetrics( qreal width, int startAngle, int spanAngle,
|
||||
Qt::SizeMode = Qt::AbsoluteSize ) noexcept;
|
||||
|
||||
bool operator==( const QskArcMetrics& ) const noexcept;
|
||||
bool operator!=( const QskArcMetrics& ) const noexcept;
|
||||
|
||||
constexpr bool isNull() const noexcept;
|
||||
|
||||
void setWidth( qreal width ) noexcept;
|
||||
constexpr qreal width() const noexcept;
|
||||
|
||||
void setStartAngle( int startAngle ) noexcept;
|
||||
constexpr int startAngle() const noexcept;
|
||||
|
||||
void setSpanAngle( int spanAngle ) noexcept;
|
||||
constexpr int spanAngle() const noexcept;
|
||||
|
||||
void setSizeMode( Qt::SizeMode ) noexcept;
|
||||
constexpr Qt::SizeMode sizeMode() const noexcept;
|
||||
|
||||
QskArcMetrics interpolated( const QskArcMetrics&,
|
||||
qreal value ) const noexcept;
|
||||
|
||||
QskArcMetrics toAbsolute( const QSizeF& ) const noexcept;
|
||||
|
||||
uint hash( uint seed = 0 ) const noexcept;
|
||||
|
||||
static QVariant interpolate( const QskArcMetrics&,
|
||||
const QskArcMetrics&, qreal progress );
|
||||
|
||||
private:
|
||||
qreal m_width;
|
||||
int m_startAngle;
|
||||
int m_spanAngle;
|
||||
Qt::SizeMode m_sizeMode;
|
||||
};
|
||||
|
||||
inline constexpr QskArcMetrics::QskArcMetrics() noexcept
|
||||
: m_width( 0 )
|
||||
, m_startAngle( 0 )
|
||||
, m_spanAngle( 0 )
|
||||
, m_sizeMode( Qt::AbsoluteSize )
|
||||
{
|
||||
}
|
||||
|
||||
inline constexpr QskArcMetrics::QskArcMetrics( qreal width,
|
||||
int startAngle, int spanAngle,
|
||||
Qt::SizeMode sizeMode ) noexcept
|
||||
: m_width( width )
|
||||
, m_startAngle( startAngle )
|
||||
, m_spanAngle( spanAngle )
|
||||
, m_sizeMode( sizeMode )
|
||||
{
|
||||
}
|
||||
|
||||
inline bool QskArcMetrics::operator==(
|
||||
const QskArcMetrics& other ) const noexcept
|
||||
{
|
||||
return ( qskFuzzyCompare( m_width, other.m_width )
|
||||
&& m_startAngle == other.m_startAngle
|
||||
&& m_spanAngle == other.m_spanAngle
|
||||
&& m_sizeMode == other.m_sizeMode );
|
||||
}
|
||||
|
||||
inline bool QskArcMetrics::operator!=(
|
||||
const QskArcMetrics& other ) const noexcept
|
||||
{
|
||||
return !( *this == other );
|
||||
}
|
||||
|
||||
inline constexpr bool QskArcMetrics::isNull() const noexcept
|
||||
{
|
||||
return ( qFuzzyIsNull( m_width )
|
||||
&& m_startAngle == 0
|
||||
&& m_spanAngle == 0
|
||||
&& m_sizeMode == Qt::AbsoluteSize );
|
||||
}
|
||||
|
||||
inline constexpr qreal QskArcMetrics::width() const noexcept
|
||||
{
|
||||
return m_width;
|
||||
}
|
||||
|
||||
inline constexpr int QskArcMetrics::startAngle() const noexcept
|
||||
{
|
||||
return m_startAngle;
|
||||
}
|
||||
|
||||
inline constexpr int QskArcMetrics::spanAngle() const noexcept
|
||||
{
|
||||
return m_spanAngle;
|
||||
}
|
||||
|
||||
inline constexpr Qt::SizeMode QskArcMetrics::sizeMode() const noexcept
|
||||
{
|
||||
return m_sizeMode;
|
||||
}
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
|
||||
class QDebug;
|
||||
QSK_EXPORT QDebug operator<<( QDebug, const QskArcMetrics& );
|
||||
|
||||
#endif
|
||||
|
||||
Q_DECLARE_TYPEINFO( QskArcMetrics, Q_MOVABLE_TYPE );
|
||||
Q_DECLARE_METATYPE( QskArcMetrics )
|
||||
|
||||
#endif
|
@ -6,6 +6,7 @@
|
||||
#include "QskSkinHintTableEditor.h"
|
||||
#include "QskSkinHintTable.h"
|
||||
|
||||
#include "QskArcMetrics.h"
|
||||
#include "QskMargins.h"
|
||||
#include "QskBoxShapeMetrics.h"
|
||||
#include "QskBoxBorderMetrics.h"
|
||||
@ -467,3 +468,27 @@ QskBoxBorderColors QskSkinHintTableEditor::boxBorderColors( QskAspect aspect ) c
|
||||
{
|
||||
return colorHint< QskBoxBorderColors >( aspectBorder( aspect ) );
|
||||
}
|
||||
|
||||
void QskSkinHintTableEditor::setArcMetrics( QskAspect aspect, qreal width,
|
||||
int startAngle, int spanAngle, Qt::SizeMode sizeMode )
|
||||
{
|
||||
setMetricHint( aspectShape( aspect ),
|
||||
QskArcMetrics( width, startAngle, spanAngle, sizeMode ) );
|
||||
}
|
||||
|
||||
void QskSkinHintTableEditor::setArcMetrics( QskAspect aspect,
|
||||
const QskArcMetrics& arcMetrics, QskStateCombination combination )
|
||||
{
|
||||
setMetricHint( aspectShape( aspect ), arcMetrics, combination );
|
||||
}
|
||||
|
||||
void QskSkinHintTableEditor::removeArcMetrics( QskAspect aspect,
|
||||
QskStateCombination combination )
|
||||
{
|
||||
return removeMetricHint( aspectShape( aspect ), combination );
|
||||
}
|
||||
|
||||
QskArcMetrics QskSkinHintTableEditor::arcMetrics( QskAspect aspect ) const
|
||||
{
|
||||
return metricHint< QskArcMetrics >( aspectShape( aspect ) );
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <qcolor.h>
|
||||
#include <qvariant.h>
|
||||
|
||||
class QskArcMetrics;
|
||||
class QskMargins;
|
||||
class QskGradient;
|
||||
class QskBoxShapeMetrics;
|
||||
@ -220,6 +221,18 @@ class QSK_EXPORT QskSkinHintTableEditor
|
||||
void removeBoxBorderColors( QskAspect, QskStateCombination = QskStateCombination() );
|
||||
QskBoxBorderColors boxBorderColors( QskAspect ) const;
|
||||
|
||||
// arcMetrics
|
||||
|
||||
void setArcMetrics( QskAspect, qreal, int, int,
|
||||
Qt::SizeMode = Qt::AbsoluteSize );
|
||||
|
||||
void setArcMetrics( QskAspect,
|
||||
const QskArcMetrics&, QskStateCombination = QskStateCombination() );
|
||||
|
||||
void removeArcMetrics( QskAspect, QskStateCombination = QskStateCombination() );
|
||||
|
||||
QskArcMetrics arcMetrics( QskAspect ) const;
|
||||
|
||||
private:
|
||||
QskSkinHintTable* m_table = nullptr;
|
||||
};
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include "QskSkinlet.h"
|
||||
|
||||
#include "QskArcNode.h"
|
||||
#include "QskAspect.h"
|
||||
#include "QskBoxBorderColors.h"
|
||||
#include "QskBoxBorderMetrics.h"
|
||||
@ -86,6 +87,12 @@ static inline bool qskIsBoxVisible( const QskBoxBorderMetrics& borderMetrics,
|
||||
return !borderMetrics.isNull() && borderColors.isVisible();
|
||||
}
|
||||
|
||||
static inline bool qskIsArcVisible( const QskArcMetrics& arcMetrics,
|
||||
const QskGradient& gradient )
|
||||
{
|
||||
return !arcMetrics.isNull() && gradient.isVisible();
|
||||
}
|
||||
|
||||
static inline QskTextColors qskTextColors(
|
||||
const QskSkinnable* skinnable, QskAspect::Subcontrol subControl )
|
||||
{
|
||||
@ -313,6 +320,90 @@ QSGNode* QskSkinlet::updateBoxNode( const QskSkinnable* skinnable,
|
||||
return boxNode;
|
||||
}
|
||||
|
||||
QSGNode* QskSkinlet::updateArcNode( const QskSkinnable* skinnable,
|
||||
QSGNode* node, QskAspect::Subcontrol subControl ) const
|
||||
{
|
||||
const auto rect = qskSubControlRect( this, skinnable, subControl );
|
||||
return updateArcNode( skinnable, node, rect, subControl );
|
||||
}
|
||||
|
||||
QSGNode* QskSkinlet::updateArcNode( const QskSkinnable* skinnable,
|
||||
QSGNode* node, const QRectF& rect, QskAspect::Subcontrol subControl )
|
||||
{
|
||||
const auto fillGradient = skinnable->gradientHint( subControl );
|
||||
return updateArcNode( skinnable, node, rect, fillGradient, subControl );
|
||||
}
|
||||
|
||||
QSGNode* QskSkinlet::updateArcNode( const QskSkinnable* skinnable,
|
||||
QSGNode* node, const QRectF& rect, const QskGradient& fillGradient,
|
||||
QskAspect::Subcontrol subControl )
|
||||
{
|
||||
auto arcMetrics = skinnable->arcMetricsHint( subControl );
|
||||
return updateArcNode( skinnable, node ,rect, fillGradient, arcMetrics,
|
||||
subControl );
|
||||
}
|
||||
|
||||
QSGNode* QskSkinlet::updateArcNode( const QskSkinnable* skinnable,
|
||||
QSGNode* node, const QRectF& rect, const QskGradient& fillGradient,
|
||||
const QskArcMetrics& arcMetrics, QskAspect::Subcontrol subControl )
|
||||
{
|
||||
const auto control = skinnable->owningControl();
|
||||
if ( control == nullptr )
|
||||
return nullptr;
|
||||
|
||||
const auto margins = skinnable->marginHint( subControl );
|
||||
|
||||
const auto arcRect = rect.marginsRemoved( margins );
|
||||
|
||||
if ( arcRect.isEmpty() )
|
||||
return nullptr;
|
||||
|
||||
auto absoluteArcMetrics = arcMetrics.toAbsolute( arcRect.size() );
|
||||
|
||||
if ( !qskIsArcVisible( arcMetrics, fillGradient ) )
|
||||
return nullptr;
|
||||
|
||||
auto arcNode = static_cast< QskArcNode* >( node );
|
||||
|
||||
if ( arcNode == nullptr )
|
||||
arcNode = new QskArcNode();
|
||||
|
||||
arcNode->setArcData( rect, absoluteArcMetrics, fillGradient,
|
||||
control->window() );
|
||||
|
||||
return arcNode;
|
||||
}
|
||||
|
||||
QSGNode* QskSkinlet::updateArcNode( const QskSkinnable* skinnable,
|
||||
QSGNode* node, int startAngle, int spanAngle,
|
||||
QskAspect::Subcontrol subControl ) const
|
||||
{
|
||||
const auto rect = qskSubControlRect( this, skinnable, subControl );
|
||||
return updateArcNode( skinnable, node, rect, startAngle, spanAngle,
|
||||
subControl );
|
||||
}
|
||||
|
||||
QSGNode* QskSkinlet::updateArcNode( const QskSkinnable* skinnable,
|
||||
QSGNode* node, const QRectF& rect, int startAngle, int spanAngle,
|
||||
QskAspect::Subcontrol subControl )
|
||||
{
|
||||
const auto fillGradient = skinnable->gradientHint( subControl );
|
||||
return updateArcNode( skinnable, node, rect, fillGradient, startAngle,
|
||||
spanAngle, subControl );
|
||||
}
|
||||
|
||||
QSGNode* QskSkinlet::updateArcNode( const QskSkinnable* skinnable,
|
||||
QSGNode* node, const QRectF& rect, const QskGradient& fillGradient,
|
||||
int startAngle, int spanAngle, QskAspect::Subcontrol subControl )
|
||||
{
|
||||
auto arcMetrics = skinnable->arcMetricsHint( subControl );
|
||||
arcMetrics.setStartAngle( startAngle );
|
||||
arcMetrics.setSpanAngle( spanAngle );
|
||||
|
||||
return updateArcNode( skinnable, node ,rect, fillGradient, arcMetrics,
|
||||
subControl );
|
||||
}
|
||||
|
||||
QSGNode* QskSkinlet::updateBoxClipNode( const QskSkinnable* skinnable,
|
||||
QSGNode* node, QskAspect::Subcontrol subControl ) const
|
||||
{
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
class QskArcMetrics;
|
||||
class QskSkin;
|
||||
class QskControl;
|
||||
class QskSkinnable;
|
||||
@ -52,6 +53,23 @@ class QSK_EXPORT QskSkinlet
|
||||
static QSGNode* updateBoxNode( const QskSkinnable*, QSGNode*,
|
||||
const QRectF&, const QskGradient&, QskAspect::Subcontrol );
|
||||
|
||||
static QSGNode* updateArcNode( const QskSkinnable*, QSGNode*,
|
||||
const QRectF&, QskAspect::Subcontrol );
|
||||
|
||||
static QSGNode* updateArcNode( const QskSkinnable*, QSGNode*,
|
||||
const QRectF&, const QskGradient&, QskAspect::Subcontrol );
|
||||
|
||||
static QSGNode* updateArcNode( const QskSkinnable*, QSGNode*,
|
||||
const QRectF&, const QskGradient&, const QskArcMetrics&,
|
||||
QskAspect::Subcontrol );
|
||||
|
||||
static QSGNode* updateArcNode( const QskSkinnable*, QSGNode*,
|
||||
const QRectF&, int startAngle, int spanAngle, QskAspect::Subcontrol );
|
||||
|
||||
static QSGNode* updateArcNode( const QskSkinnable*, QSGNode*,
|
||||
const QRectF&, const QskGradient&, int startAngle, int spanAngle,
|
||||
QskAspect::Subcontrol );
|
||||
|
||||
static QSGNode* updateTextNode( const QskSkinnable*, QSGNode*,
|
||||
const QRectF&, Qt::Alignment, const QString&, const QskTextOptions&,
|
||||
QskAspect::Subcontrol );
|
||||
@ -85,6 +103,13 @@ class QSK_EXPORT QskSkinlet
|
||||
QSGNode* updateBoxNode( const QskSkinnable*, QSGNode*,
|
||||
QskAspect::Subcontrol ) const;
|
||||
|
||||
QSGNode* updateArcNode( const QskSkinnable*, QSGNode*,
|
||||
QskAspect::Subcontrol ) const;
|
||||
|
||||
QSGNode* updateArcNode( const QskSkinnable*, QSGNode*,
|
||||
int startAngle, int spanAngle,
|
||||
QskAspect::Subcontrol ) const;
|
||||
|
||||
QSGNode* updateBoxClipNode( const QskSkinnable*, QSGNode*,
|
||||
QskAspect::Subcontrol ) const;
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "QskSkinnable.h"
|
||||
|
||||
#include "QskAnimationHint.h"
|
||||
#include "QskArcMetrics.h"
|
||||
#include "QskAspect.h"
|
||||
#include "QskColorFilter.h"
|
||||
#include "QskControl.h"
|
||||
@ -521,6 +522,24 @@ QskBoxBorderColors QskSkinnable::boxBorderColorsHint(
|
||||
this, aspect | QskAspect::Border, status );
|
||||
}
|
||||
|
||||
bool QskSkinnable::setArcMetricsHint(
|
||||
const QskAspect aspect, const QskArcMetrics& arc )
|
||||
{
|
||||
return qskSetMetric( this, aspect | QskAspect::Shape, arc );
|
||||
}
|
||||
|
||||
bool QskSkinnable::resetArcMetricsHint( const QskAspect aspect )
|
||||
{
|
||||
return resetMetric( aspect | QskAspect::Shape );
|
||||
}
|
||||
|
||||
QskArcMetrics QskSkinnable::arcMetricsHint(
|
||||
const QskAspect aspect, QskSkinHintStatus* status ) const
|
||||
{
|
||||
return qskMetric< QskArcMetrics >(
|
||||
this, aspect | QskAspect::Shape, status );
|
||||
}
|
||||
|
||||
bool QskSkinnable::setSpacingHint( const QskAspect aspect, qreal spacing )
|
||||
{
|
||||
return qskSetMetric( this, aspect | QskAspect::Spacing, spacing );
|
||||
|
@ -21,6 +21,7 @@ class QDebug;
|
||||
|
||||
class QSGNode;
|
||||
|
||||
class QskArcMetrics;
|
||||
class QskControl;
|
||||
class QskAnimationHint;
|
||||
class QskColorFilter;
|
||||
@ -189,6 +190,10 @@ class QSK_EXPORT QskSkinnable
|
||||
bool resetBoxBorderColorsHint( QskAspect );
|
||||
QskBoxBorderColors boxBorderColorsHint( QskAspect, QskSkinHintStatus* = nullptr ) const;
|
||||
|
||||
bool setArcMetricsHint( QskAspect, const QskArcMetrics& );
|
||||
bool resetArcMetricsHint( QskAspect );
|
||||
QskArcMetrics arcMetricsHint( QskAspect, QskSkinHintStatus* = nullptr ) const;
|
||||
|
||||
bool setSpacingHint( QskAspect, qreal );
|
||||
bool resetSpacingHint( QskAspect );
|
||||
qreal spacingHint( QskAspect, QskSkinHintStatus* = nullptr ) const;
|
||||
|
43
src/nodes/QskArcNode.cpp
Normal file
43
src/nodes/QskArcNode.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
/**********************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "QskArcNode.h"
|
||||
#include "QskArcRenderer.h"
|
||||
|
||||
QskArcNode::QskArcNode()
|
||||
{
|
||||
}
|
||||
|
||||
QskArcNode::~QskArcNode()
|
||||
{
|
||||
}
|
||||
|
||||
void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& metrics,
|
||||
const QskGradient &gradient, QQuickWindow* window )
|
||||
{
|
||||
m_metrics = metrics;
|
||||
m_gradient = gradient;
|
||||
|
||||
update( window, QskTextureRenderer::AutoDetect, rect.toRect() );
|
||||
}
|
||||
|
||||
void QskArcNode::paint( QPainter* painter, const QSizeF &size )
|
||||
{
|
||||
const qreal w = m_metrics.width();
|
||||
const QRectF rect( 0.5 * w, 0.5 * w, size.width() - w, size.height() - w );
|
||||
|
||||
QskArcRenderer renderer;
|
||||
renderer.renderArc( rect, m_metrics, m_gradient, painter );
|
||||
}
|
||||
|
||||
uint QskArcNode::hash() const
|
||||
{
|
||||
uint h = m_metrics.hash();
|
||||
|
||||
for( const auto& stop : m_gradient.stops() )
|
||||
h = stop.hash( h );
|
||||
|
||||
return h;
|
||||
}
|
30
src/nodes/QskArcNode.h
Normal file
30
src/nodes/QskArcNode.h
Normal file
@ -0,0 +1,30 @@
|
||||
/**********************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QSK_ARC_NODE_H
|
||||
#define QSK_ARC_NODE_H
|
||||
|
||||
#include "QskArcMetrics.h"
|
||||
#include "QskGradient.h"
|
||||
#include "QskPaintedNode.h"
|
||||
|
||||
class QSK_EXPORT QskArcNode : public QskPaintedNode
|
||||
{
|
||||
public:
|
||||
QskArcNode();
|
||||
~QskArcNode() override;
|
||||
|
||||
void setArcData( const QRectF&, const QskArcMetrics&, const QskGradient&,
|
||||
QQuickWindow* );
|
||||
|
||||
void paint( QPainter* painter, const QSizeF& size ) override;
|
||||
uint hash() const override;
|
||||
|
||||
private:
|
||||
QskArcMetrics m_metrics;
|
||||
QskGradient m_gradient;
|
||||
};
|
||||
|
||||
#endif
|
51
src/nodes/QskArcRenderer.cpp
Normal file
51
src/nodes/QskArcRenderer.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "QskArcRenderer.h"
|
||||
#include "QskArcMetrics.h"
|
||||
#include "QskGradient.h"
|
||||
|
||||
#include <qpainter.h>
|
||||
#include <qrect.h>
|
||||
|
||||
void QskArcRenderer::renderArc(const QRectF& rect,
|
||||
const QskArcMetrics& metrics, const QskGradient& gradient,
|
||||
QPainter* painter )
|
||||
{
|
||||
painter->setRenderHint( QPainter::Antialiasing, true );
|
||||
|
||||
QGradientStops stops;
|
||||
|
||||
for( const QskGradientStop& stop : gradient.stops() )
|
||||
{
|
||||
QGradientStop s( stop.position(), stop.color() );
|
||||
stops.append( s );
|
||||
}
|
||||
|
||||
/*
|
||||
horizontal is interpreted as in direction of the arc,
|
||||
while vertical means from the inner to the outer border
|
||||
*/
|
||||
|
||||
QBrush brush;
|
||||
|
||||
if( gradient.orientation() == QskGradient::Vertical )
|
||||
{
|
||||
QRadialGradient gradient( rect.center(), qMin( rect.width(), rect.height() ) );
|
||||
gradient.setStops( stops );
|
||||
|
||||
brush = gradient;
|
||||
}
|
||||
else
|
||||
{
|
||||
QConicalGradient gradient( rect.center(), metrics.startAngle() / 16.0 );
|
||||
gradient.setStops( stops );
|
||||
|
||||
brush = gradient;
|
||||
}
|
||||
|
||||
painter->setPen( QPen( brush, metrics.width(), Qt::SolidLine, Qt::FlatCap ) );
|
||||
painter->drawArc( rect, metrics.startAngle(), metrics.spanAngle() );
|
||||
}
|
24
src/nodes/QskArcRenderer.h
Normal file
24
src/nodes/QskArcRenderer.h
Normal file
@ -0,0 +1,24 @@
|
||||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QSK_ARC_RENDERER_H
|
||||
#define QSK_ARC_RENDERER_H
|
||||
|
||||
#include "QskGlobal.h"
|
||||
|
||||
class QskArcMetrics;
|
||||
class QskGradient;
|
||||
|
||||
class QPainter;
|
||||
class QRectF;
|
||||
|
||||
class QSK_EXPORT QskArcRenderer
|
||||
{
|
||||
public:
|
||||
void renderArc( const QRectF&, const QskArcMetrics&,
|
||||
const QskGradient&, QPainter* );
|
||||
};
|
||||
|
||||
#endif
|
@ -12,6 +12,7 @@ DEPENDPATH *= $${QSK_SUBDIRS}
|
||||
# DEFINES += QSK_LAYOUT_COMPAT
|
||||
|
||||
HEADERS += \
|
||||
common/QskArcMetrics.h \
|
||||
common/QskAspect.h \
|
||||
common/QskBoxBorderColors.h \
|
||||
common/QskBoxBorderMetrics.h \
|
||||
@ -38,6 +39,7 @@ HEADERS += \
|
||||
common/QskTextOptions.h
|
||||
|
||||
SOURCES += \
|
||||
common/QskArcMetrics.cpp \
|
||||
common/QskAspect.cpp \
|
||||
common/QskBoxBorderColors.cpp \
|
||||
common/QskBoxBorderMetrics.cpp \
|
||||
@ -85,6 +87,8 @@ SOURCES += \
|
||||
graphic/QskStandardSymbol.cpp
|
||||
|
||||
HEADERS += \
|
||||
nodes/QskArcNode.h \
|
||||
nodes/QskArcRenderer.h \
|
||||
nodes/QskBoxNode.h \
|
||||
nodes/QskBoxClipNode.h \
|
||||
nodes/QskBoxRenderer.h \
|
||||
@ -103,6 +107,8 @@ HEADERS += \
|
||||
nodes/QskVertex.h
|
||||
|
||||
SOURCES += \
|
||||
nodes/QskArcNode.cpp \
|
||||
nodes/QskArcRenderer.cpp \
|
||||
nodes/QskBoxNode.cpp \
|
||||
nodes/QskBoxClipNode.cpp \
|
||||
nodes/QskBoxRendererRect.cpp \
|
||||
|
Loading…
x
Reference in New Issue
Block a user