2022-04-04 12:14:07 +00:00
|
|
|
/******************************************************************************
|
|
|
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
|
|
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
|
|
|
*****************************************************************************/
|
|
|
|
|
2022-04-04 06:53:20 +00:00
|
|
|
#include "QskCheckBoxSkinlet.h"
|
|
|
|
#include "QskCheckBox.h"
|
2022-04-05 08:15:08 +00:00
|
|
|
#include "QskSGNode.h"
|
2022-07-01 09:10:59 +00:00
|
|
|
#include "QskTextOptions.h"
|
|
|
|
#include "QskFunctions.h"
|
2022-04-04 06:53:20 +00:00
|
|
|
|
|
|
|
#include <QSGFlatColorMaterial>
|
|
|
|
#include <qsgnode.h>
|
|
|
|
|
2022-04-04 12:14:07 +00:00
|
|
|
namespace
|
|
|
|
{
|
2022-04-05 08:15:08 +00:00
|
|
|
class IndicatorNode : public QSGGeometryNode
|
2022-04-04 12:14:07 +00:00
|
|
|
{
|
|
|
|
public:
|
2022-04-05 08:15:08 +00:00
|
|
|
IndicatorNode()
|
|
|
|
: m_geometry( QSGGeometry::defaultAttributes_Point2D(), 3 )
|
2022-04-04 12:14:07 +00:00
|
|
|
{
|
2022-04-05 08:15:08 +00:00
|
|
|
m_geometry.setDrawingMode( QSGGeometry::DrawLineStrip );
|
|
|
|
m_geometry.setLineWidth( 2 );
|
|
|
|
setGeometry( &m_geometry );
|
2022-04-04 06:53:20 +00:00
|
|
|
|
2022-04-05 08:15:08 +00:00
|
|
|
setMaterial( &m_material );
|
2022-04-04 12:14:07 +00:00
|
|
|
}
|
2022-04-04 06:53:20 +00:00
|
|
|
|
2022-07-01 09:10:59 +00:00
|
|
|
void update( const QRectF& rect, const QColor& color )
|
2022-04-04 16:32:17 +00:00
|
|
|
{
|
2022-04-05 08:15:08 +00:00
|
|
|
if ( color != m_material.color() )
|
|
|
|
{
|
|
|
|
m_material.setColor( color );
|
|
|
|
markDirty( QSGNode::DirtyMaterial );
|
|
|
|
}
|
|
|
|
|
2022-07-01 09:10:59 +00:00
|
|
|
if ( rect != m_rect )
|
2022-04-05 08:15:08 +00:00
|
|
|
{
|
|
|
|
m_rect = rect;
|
|
|
|
|
|
|
|
const auto x = rect.x();
|
|
|
|
const auto y = rect.y();
|
|
|
|
const auto w = rect.width();
|
|
|
|
const auto h = rect.height();
|
|
|
|
|
|
|
|
auto points = m_geometry.vertexDataAsPoint2D();
|
|
|
|
|
2022-07-01 09:10:59 +00:00
|
|
|
points[0].set( x, y + h / 2 );
|
|
|
|
points[1].set( x + w / 3, y + h );
|
|
|
|
points[2].set( x + w, y );
|
2022-04-08 14:46:20 +00:00
|
|
|
|
2022-04-05 08:15:08 +00:00
|
|
|
markDirty( QSGNode::DirtyGeometry );
|
|
|
|
}
|
2022-04-04 12:14:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2022-04-05 08:15:08 +00:00
|
|
|
QSGFlatColorMaterial m_material;
|
|
|
|
QSGGeometry m_geometry;
|
|
|
|
|
|
|
|
QRectF m_rect;
|
2022-04-04 12:14:07 +00:00
|
|
|
};
|
|
|
|
}
|
2022-04-04 06:53:20 +00:00
|
|
|
|
|
|
|
QskCheckBoxSkinlet::QskCheckBoxSkinlet( QskSkin* skin )
|
|
|
|
: QskSkinlet( skin )
|
|
|
|
{
|
2022-07-01 09:10:59 +00:00
|
|
|
setNodeRoles( { BoxRole, IndicatorRole, TextRole } );
|
2022-04-04 06:53:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QskCheckBoxSkinlet::~QskCheckBoxSkinlet()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2022-04-05 08:15:08 +00:00
|
|
|
QRectF QskCheckBoxSkinlet::subControlRect( const QskSkinnable* skinnable,
|
|
|
|
const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const
|
2022-04-04 06:53:20 +00:00
|
|
|
{
|
2022-07-01 09:10:59 +00:00
|
|
|
const auto checkBox = static_cast< const QskCheckBox* >( skinnable );
|
|
|
|
|
|
|
|
if ( subControl == QskCheckBox::Panel )
|
|
|
|
{
|
|
|
|
return contentsRect;
|
|
|
|
}
|
|
|
|
else if ( subControl == QskCheckBox::Box )
|
|
|
|
{
|
|
|
|
return boxRect( checkBox, contentsRect );
|
|
|
|
}
|
|
|
|
else if ( subControl == QskCheckBox::Indicator )
|
|
|
|
{
|
|
|
|
const auto boxRect = subControlRect( skinnable, contentsRect, QskCheckBox::Box );
|
|
|
|
return skinnable->innerBox( QskCheckBox::Box, boxRect );
|
|
|
|
|
|
|
|
return skinnable->innerBox( QskCheckBox::Box, contentsRect );
|
|
|
|
}
|
|
|
|
else if ( subControl == QskCheckBox::Text )
|
|
|
|
{
|
|
|
|
return textRect( checkBox, contentsRect );
|
|
|
|
}
|
2022-04-05 08:15:08 +00:00
|
|
|
|
2022-04-04 06:53:20 +00:00
|
|
|
return contentsRect;
|
|
|
|
}
|
|
|
|
|
2022-07-01 09:10:59 +00:00
|
|
|
QRectF QskCheckBoxSkinlet::textRect(
|
|
|
|
const QskCheckBox* checkBox, const QRectF& contentsRect ) const
|
|
|
|
{
|
|
|
|
const auto boxRect = subControlRect( checkBox, contentsRect, QskCheckBox::Box );
|
|
|
|
const qreal spacing = checkBox->spacingHint( QskCheckBox::Panel );
|
|
|
|
|
|
|
|
auto r = subControlRect( checkBox, contentsRect, QskCheckBox::Panel );
|
|
|
|
r = checkBox->innerBox( QskCheckBox::Panel, r );
|
|
|
|
|
|
|
|
if ( checkBox->layoutMirroring() )
|
|
|
|
r.setRight( boxRect.left() - spacing );
|
|
|
|
else
|
|
|
|
r.setLeft( boxRect.right() + spacing );
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
QRectF QskCheckBoxSkinlet::boxRect(
|
|
|
|
const QskCheckBox* checkBox, const QRectF& contentsRect ) const
|
|
|
|
{
|
|
|
|
const auto size = checkBox->strutSizeHint( QskCheckBox::Box );
|
|
|
|
|
|
|
|
auto r = checkBox->innerBox( QskCheckBox::Panel, contentsRect );
|
|
|
|
|
|
|
|
if ( checkBox->layoutMirroring() )
|
|
|
|
r.setLeft( r.right() - size.width() );
|
|
|
|
else
|
|
|
|
r.setWidth( size.width() );
|
|
|
|
|
|
|
|
r.setTop( r.top() + 0.5 * ( r.height() - size.height() ) );
|
|
|
|
r.setHeight( size.height() );
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2022-04-04 06:53:20 +00:00
|
|
|
QSGNode* QskCheckBoxSkinlet::updateSubNode(
|
|
|
|
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const
|
|
|
|
{
|
2022-04-05 08:15:08 +00:00
|
|
|
auto checkBox = static_cast< const QskCheckBox* >( skinnable );
|
|
|
|
|
2022-04-04 12:14:07 +00:00
|
|
|
switch( nodeRole )
|
|
|
|
{
|
2022-04-05 08:15:08 +00:00
|
|
|
case PanelRole:
|
|
|
|
return updateBoxNode( skinnable, node, QskCheckBox::Panel );
|
2022-04-04 12:14:07 +00:00
|
|
|
|
2022-07-01 09:10:59 +00:00
|
|
|
case BoxRole:
|
|
|
|
return updateBoxNode( skinnable, node, QskCheckBox::Box );
|
|
|
|
|
2022-04-05 08:15:08 +00:00
|
|
|
case IndicatorRole:
|
|
|
|
return updateIndicatorNode( checkBox, node );
|
2022-07-01 09:10:59 +00:00
|
|
|
|
|
|
|
case TextRole:
|
|
|
|
return updateTextNode( checkBox, node );
|
2022-04-04 06:53:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return Inherited::updateSubNode( skinnable, nodeRole, node );
|
|
|
|
}
|
|
|
|
|
2022-04-05 08:15:08 +00:00
|
|
|
QSGNode* QskCheckBoxSkinlet::updateIndicatorNode(
|
2022-04-04 12:14:07 +00:00
|
|
|
const QskCheckBox* checkBox, QSGNode* node ) const
|
|
|
|
{
|
|
|
|
using Q = QskCheckBox;
|
|
|
|
|
2022-07-01 09:10:59 +00:00
|
|
|
if ( !checkBox->isChecked() )
|
2022-04-04 16:32:17 +00:00
|
|
|
return nullptr;
|
|
|
|
|
2022-04-05 08:15:08 +00:00
|
|
|
const auto rect = checkBox->subControlRect( Q::Indicator );
|
|
|
|
if ( rect.isEmpty() )
|
|
|
|
return nullptr;
|
2022-04-04 12:14:07 +00:00
|
|
|
|
2022-04-05 08:15:08 +00:00
|
|
|
auto indicatorNode = QskSGNode::ensureNode< IndicatorNode >( node );
|
2022-07-01 09:10:59 +00:00
|
|
|
indicatorNode->update( rect, checkBox->color( Q::Indicator ) );
|
2022-04-04 12:14:07 +00:00
|
|
|
|
2022-04-05 08:15:08 +00:00
|
|
|
return indicatorNode;
|
2022-04-04 12:14:07 +00:00
|
|
|
}
|
|
|
|
|
2022-07-01 09:10:59 +00:00
|
|
|
QSGNode* QskCheckBoxSkinlet::updateTextNode(
|
|
|
|
const QskCheckBox* checkBox, QSGNode* node ) const
|
|
|
|
{
|
|
|
|
using Q = QskCheckBox;
|
|
|
|
|
|
|
|
const auto rect = checkBox->subControlRect( Q::Text );
|
|
|
|
const auto alignH = checkBox->layoutMirroring() ? Qt::AlignRight : Qt::AlignLeft;
|
|
|
|
|
|
|
|
QskTextOptions textOptions;
|
|
|
|
textOptions.setElideMode( Qt::ElideMiddle );
|
|
|
|
|
|
|
|
return QskSkinlet::updateTextNode( checkBox, node, rect, alignH | Qt::AlignVCenter,
|
|
|
|
checkBox->text(), textOptions, QskCheckBox::Text );
|
|
|
|
}
|
|
|
|
|
2022-04-04 06:53:20 +00:00
|
|
|
QSizeF QskCheckBoxSkinlet::sizeHint( const QskSkinnable* skinnable,
|
2022-07-01 09:10:59 +00:00
|
|
|
Qt::SizeHint which, const QSizeF& ) const
|
2022-04-04 06:53:20 +00:00
|
|
|
{
|
2022-07-01 09:10:59 +00:00
|
|
|
using Q = QskCheckBox;
|
|
|
|
|
|
|
|
if ( which == Qt::MaximumSize )
|
|
|
|
return QSizeF();
|
|
|
|
|
|
|
|
auto checkBox = static_cast< const QskCheckBox* >( skinnable );
|
|
|
|
|
|
|
|
auto size = skinnable->strutSizeHint( QskCheckBox::Box );
|
|
|
|
size = skinnable->outerBoxSize( Q::Panel, size );
|
|
|
|
|
|
|
|
auto text = checkBox->text();
|
|
|
|
if ( !text.isEmpty() )
|
|
|
|
{
|
|
|
|
qreal extra = skinnable->spacingHint( Q::Panel );
|
|
|
|
|
|
|
|
if ( which == Qt::MinimumSize )
|
|
|
|
text = 'W';
|
|
|
|
|
|
|
|
const auto font = skinnable->effectiveFont( Q::Text );
|
|
|
|
extra += qskHorizontalAdvance( font, text );
|
|
|
|
|
|
|
|
size.setWidth( size.width() + extra );
|
|
|
|
}
|
|
|
|
|
|
|
|
return size.expandedTo( skinnable->strutSizeHint( Q::Panel ) );
|
2022-04-04 06:53:20 +00:00
|
|
|
}
|
2022-04-20 11:54:27 +00:00
|
|
|
|
|
|
|
#include "moc_QskCheckBoxSkinlet.cpp"
|