QskCheckBox improvements

This commit is contained in:
Uwe Rathmann 2022-04-05 10:15:08 +02:00
parent 6ef1f8a45d
commit 8c2093d151
2 changed files with 69 additions and 72 deletions

View File

@ -5,132 +5,129 @@
#include "QskCheckBoxSkinlet.h" #include "QskCheckBoxSkinlet.h"
#include "QskCheckBox.h" #include "QskCheckBox.h"
#include "QskSGNode.h"
#include <QSGFlatColorMaterial> #include <QSGFlatColorMaterial>
#include <qsgnode.h> #include <qsgnode.h>
namespace namespace
{ {
class Tick : public QSGGeometryNode class IndicatorNode : public QSGGeometryNode
{ {
public: public:
Tick() IndicatorNode()
: geometry( QSGGeometry::defaultAttributes_Point2D(), 3 ) : m_geometry( QSGGeometry::defaultAttributes_Point2D(), 3 )
{ {
geometry.setDrawingMode( QSGGeometry::DrawLineStrip ); m_geometry.setDrawingMode( QSGGeometry::DrawLineStrip );
geometry.setLineWidth( 2 ); m_geometry.setLineWidth( 2 );
setGeometry( &geometry ); setGeometry( &m_geometry );
setMaterial( &material ); setMaterial( &m_material );
} }
void setColor( const QColor& color ) void update( bool isPartially, const QRectF& rect, const QColor& color )
{ {
material.setColor( color ); if ( color != m_material.color() )
markDirty( QSGNode::DirtyMaterial ); {
} m_material.setColor( color );
markDirty( QSGNode::DirtyMaterial );
}
void makeTick( const QRectF& rect ) if ( rect != m_rect || isPartially != m_isPartially )
{ {
const auto x = rect.x(); m_rect = rect;
const auto y = rect.y(); m_isPartially = isPartially;
auto vertexData = geometry.vertexDataAsPoint2D(); const auto x = rect.x();
const auto y = rect.y();
const auto w = rect.width();
const auto h = rect.height();
vertexData[0].set( x, y + rect.height() / 2 ); auto points = m_geometry.vertexDataAsPoint2D();
vertexData[1].set( x + rect.width() / 3, y + rect.height() );
vertexData[2].set( x + rect.width(), y );
markDirty( QSGNode::DirtyGeometry ); if ( isPartially )
} {
points[0].set( x, y + h / 2 );
points[1] = points[0];
points[2].set( x + w, y + h / 2 );
}
else
{
points[0].set( x, y + h / 2 );
points[1].set( x + w / 3, y + h );
points[2].set( x + w, y );
}
void makePartially( const QRectF& rect ) markDirty( QSGNode::DirtyGeometry );
{ }
const auto x = rect.x();
const auto y = rect.y();
auto vertexData = geometry.vertexDataAsPoint2D();
vertexData[0].set( x, y + rect.height() / 2 );
vertexData[1].set( x, y + rect.height() / 2 );
vertexData[2].set( x + rect.width(), y + rect.height() / 2 );
markDirty( QSGNode::DirtyGeometry );
} }
private: private:
QSGFlatColorMaterial material; QSGFlatColorMaterial m_material;
QSGGeometry geometry; QSGGeometry m_geometry;
QRectF m_rect;
bool m_isPartially;
}; };
} }
QskCheckBoxSkinlet::QskCheckBoxSkinlet( QskSkin* skin ) QskCheckBoxSkinlet::QskCheckBoxSkinlet( QskSkin* skin )
: QskSkinlet( skin ) : QskSkinlet( skin )
{ {
setNodeRoles( { BoxRole, TickRole } ); setNodeRoles( { PanelRole, IndicatorRole } );
} }
QskCheckBoxSkinlet::~QskCheckBoxSkinlet() QskCheckBoxSkinlet::~QskCheckBoxSkinlet()
{ {
} }
QRectF QskCheckBoxSkinlet::subControlRect( QRectF QskCheckBoxSkinlet::subControlRect( const QskSkinnable* skinnable,
const QskSkinnable*, const QRectF& contentsRect, QskAspect::Subcontrol ) const const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const
{ {
if ( subControl == QskCheckBox::Indicator )
return skinnable->innerBox( QskCheckBox::Panel, contentsRect );
return contentsRect; return contentsRect;
} }
QSGNode* QskCheckBoxSkinlet::updateSubNode( QSGNode* QskCheckBoxSkinlet::updateSubNode(
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const
{ {
auto checkBox = static_cast< const QskCheckBox* >( skinnable );
switch( nodeRole ) switch( nodeRole )
{ {
case BoxRole: case PanelRole:
{ return updateBoxNode( skinnable, node, QskCheckBox::Panel );
return updateBoxNode( skinnable, node, QskCheckBox::Box );
}
case TickRole: case IndicatorRole:
{ return updateIndicatorNode( checkBox, node );
auto checkBox = static_cast< const QskCheckBox* >( skinnable );
return updateTickNode( checkBox, node );
}
} }
return Inherited::updateSubNode( skinnable, nodeRole, node ); return Inherited::updateSubNode( skinnable, nodeRole, node );
} }
QSGNode* QskCheckBoxSkinlet::updateTickNode( QSGNode* QskCheckBoxSkinlet::updateIndicatorNode(
const QskCheckBox* checkBox, QSGNode* node ) const const QskCheckBox* checkBox, QSGNode* node ) const
{ {
using Q = QskCheckBox; using Q = QskCheckBox;
if ( checkBox->checkState() == Qt::Unchecked ) const auto state = checkBox->checkState();
if ( state == Qt::Unchecked )
return nullptr; return nullptr;
auto rect = checkBox->subControlRect( Q::Tick ); const auto rect = checkBox->subControlRect( Q::Indicator );
rect = rect.marginsRemoved( checkBox->marginHint( Q::Tick ) ); if ( rect.isEmpty() )
return nullptr;
auto tick = static_cast< Tick* >( node ); auto indicatorNode = QskSGNode::ensureNode< IndicatorNode >( node );
if ( tick == nullptr ) indicatorNode->update( state != Qt::Checked, rect, checkBox->color( Q::Indicator ) );
tick = new Tick();
if ( checkBox->checkState() == Qt::PartiallyChecked ) return indicatorNode;
{
tick->setColor( checkBox->color( Q::Tick | Q::PartiallyChecked ) );
tick->makePartially( rect );
}
else
{
tick->setColor( checkBox->color( Q::Tick | Q::Checked ) );
tick->makeTick( rect );
}
return tick;
} }
QSizeF QskCheckBoxSkinlet::sizeHint( const QskSkinnable* skinnable, QSizeF QskCheckBoxSkinlet::sizeHint( const QskSkinnable* skinnable,
Qt::SizeHint, const QSizeF& ) const Qt::SizeHint, const QSizeF& ) const
{ {
return skinnable->strutSizeHint( QskCheckBox::Box ); return skinnable->strutSizeHint( QskCheckBox::Panel );
} }

View File

@ -19,8 +19,8 @@ class QSK_EXPORT QskCheckBoxSkinlet : public QskSkinlet
public: public:
enum NodeRole enum NodeRole
{ {
BoxRole, PanelRole,
TickRole, IndicatorRole,
}; };
Q_INVOKABLE QskCheckBoxSkinlet( QskSkin* = nullptr ); Q_INVOKABLE QskCheckBoxSkinlet( QskSkin* = nullptr );
@ -36,8 +36,8 @@ class QSK_EXPORT QskCheckBoxSkinlet : public QskSkinlet
QSGNode* updateSubNode( const QskSkinnable*, QSGNode* updateSubNode( const QskSkinnable*,
quint8 nodeRole, QSGNode* ) const override; quint8 nodeRole, QSGNode* ) const override;
private: protected:
QSGNode* updateTickNode( const QskCheckBox*, QSGNode* ) const; virtual QSGNode* updateIndicatorNode( const QskCheckBox*, QSGNode* ) const;
}; };
#endif #endif