2023-02-17 12:01:56 +01:00
|
|
|
/******************************************************************************
|
2023-02-17 14:05:05 +01:00
|
|
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
|
|
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
2023-02-17 12:01:56 +01:00
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
#include "QskSpinBoxSkinlet.h"
|
|
|
|
#include "QskSpinBox.h"
|
2023-02-27 09:56:41 +01:00
|
|
|
#include "QskFunctions.h"
|
2023-03-01 16:09:17 +01:00
|
|
|
#include "QskSkinStateChanger.h"
|
2023-02-19 14:24:09 +01:00
|
|
|
|
2023-02-27 09:56:41 +01:00
|
|
|
#include <qfontmetrics.h>
|
2023-02-17 12:01:56 +01:00
|
|
|
|
2023-03-01 16:09:17 +01:00
|
|
|
static inline QskAspect::States qskButtonStates(
|
|
|
|
const QskSkinnable* skinnable, QskAspect::Subcontrol subControl )
|
|
|
|
{
|
|
|
|
using Q = QskSpinBox;
|
|
|
|
|
|
|
|
auto spinBox = static_cast< const QskSpinBox* >( skinnable );
|
|
|
|
|
|
|
|
auto states = spinBox->skinStates();
|
|
|
|
|
|
|
|
if ( spinBox->isEnabled() && !spinBox->isWrapping() )
|
|
|
|
{
|
|
|
|
if ( subControl == Q::DownIndicator || subControl == Q::DownPanel )
|
|
|
|
{
|
|
|
|
if ( spinBox->value() <= spinBox->minimum() )
|
|
|
|
states |= QskControl::Disabled;
|
|
|
|
}
|
|
|
|
else if ( subControl == Q::UpIndicator || subControl == Q::UpPanel )
|
|
|
|
{
|
|
|
|
if ( spinBox->value() >= spinBox->maximum() )
|
|
|
|
states |= QskControl::Disabled;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return states;
|
|
|
|
}
|
|
|
|
|
2023-02-17 15:22:40 +01:00
|
|
|
QskSpinBoxSkinlet::QskSpinBoxSkinlet( QskSkin* )
|
2023-02-17 12:01:56 +01:00
|
|
|
{
|
2023-02-23 14:37:49 +01:00
|
|
|
setNodeRoles( { UpPanel, DownPanel, TextPanel,
|
|
|
|
UpIndicator, DownIndicator, Text } );
|
2023-02-17 12:01:56 +01:00
|
|
|
}
|
|
|
|
|
2023-02-19 14:24:09 +01:00
|
|
|
QRectF QskSpinBoxSkinlet::subControlRect( const QskSkinnable* skinnable,
|
|
|
|
const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const
|
|
|
|
{
|
|
|
|
using Q = QskSpinBox;
|
|
|
|
|
2023-03-01 16:09:17 +01:00
|
|
|
QskSkinStateChanger stateChanger( skinnable );
|
|
|
|
stateChanger.setStates( qskButtonStates( skinnable, subControl ) );
|
|
|
|
|
2023-02-23 14:37:49 +01:00
|
|
|
if ( subControl == Q::DownIndicator )
|
|
|
|
return skinnable->subControlContentsRect( contentsRect, Q::DownPanel );
|
2023-02-19 14:24:09 +01:00
|
|
|
|
2023-02-23 14:37:49 +01:00
|
|
|
if ( subControl == Q::UpIndicator )
|
|
|
|
return skinnable->subControlContentsRect( contentsRect, Q::UpPanel );
|
2023-02-19 14:24:09 +01:00
|
|
|
|
|
|
|
if ( subControl == Q::Text )
|
|
|
|
return skinnable->subControlContentsRect( contentsRect, Q::TextPanel );
|
|
|
|
|
2023-02-27 09:56:41 +01:00
|
|
|
if ( subControl == Q::DownPanel || subControl == Q::UpPanel )
|
|
|
|
return buttonRect( skinnable, contentsRect, subControl );
|
2023-02-19 14:24:09 +01:00
|
|
|
|
|
|
|
if ( subControl == Q::TextPanel )
|
2023-02-27 09:56:41 +01:00
|
|
|
return textPanelRect( skinnable, contentsRect );
|
2023-02-17 15:22:40 +01:00
|
|
|
|
2023-02-19 14:24:09 +01:00
|
|
|
return Inherited::subControlRect( skinnable, contentsRect, subControl );
|
2023-02-17 12:01:56 +01:00
|
|
|
}
|
|
|
|
|
2023-02-17 15:22:40 +01:00
|
|
|
QSGNode* QskSpinBoxSkinlet::updateSubNode(
|
2023-02-19 14:24:09 +01:00
|
|
|
const QskSkinnable* skinnable, const quint8 nodeRole, QSGNode* const node ) const
|
2023-02-17 12:01:56 +01:00
|
|
|
{
|
2023-02-19 14:24:09 +01:00
|
|
|
using Q = QskSpinBox;
|
|
|
|
|
2023-03-01 16:09:17 +01:00
|
|
|
QskSkinStateChanger stateChanger( skinnable );
|
|
|
|
|
2023-02-19 14:24:09 +01:00
|
|
|
switch( nodeRole )
|
2023-02-17 15:22:40 +01:00
|
|
|
{
|
2023-02-23 14:37:49 +01:00
|
|
|
case UpPanel:
|
2023-03-01 16:09:17 +01:00
|
|
|
{
|
|
|
|
stateChanger.setStates( qskButtonStates( skinnable, Q::UpPanel ) );
|
2023-02-23 14:37:49 +01:00
|
|
|
return updateBoxNode( skinnable, node, Q::UpPanel );
|
2023-03-01 16:09:17 +01:00
|
|
|
}
|
2023-02-19 14:24:09 +01:00
|
|
|
|
2023-02-23 14:37:49 +01:00
|
|
|
case DownPanel:
|
2023-03-01 16:09:17 +01:00
|
|
|
{
|
|
|
|
stateChanger.setStates( qskButtonStates( skinnable, Q::DownPanel ) );
|
2023-02-23 14:37:49 +01:00
|
|
|
return updateBoxNode( skinnable, node, Q::DownPanel );
|
2023-03-01 16:09:17 +01:00
|
|
|
}
|
2023-02-19 14:24:09 +01:00
|
|
|
|
2023-02-23 14:37:49 +01:00
|
|
|
case UpIndicator:
|
2023-02-19 14:24:09 +01:00
|
|
|
{
|
2023-03-01 16:09:17 +01:00
|
|
|
stateChanger.setStates( qskButtonStates( skinnable, Q::UpIndicator ) );
|
2023-03-02 14:56:30 +01:00
|
|
|
return updateSymbolNode( skinnable, node, Q::UpIndicator );
|
2023-02-19 14:24:09 +01:00
|
|
|
}
|
|
|
|
|
2023-02-23 14:37:49 +01:00
|
|
|
case DownIndicator:
|
2023-02-19 14:24:09 +01:00
|
|
|
{
|
2023-03-01 16:09:17 +01:00
|
|
|
stateChanger.setStates( qskButtonStates( skinnable, Q::DownIndicator ) );
|
2023-03-02 14:56:30 +01:00
|
|
|
return updateSymbolNode( skinnable, node, Q::DownIndicator );
|
2023-02-19 14:24:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
case TextPanel:
|
2023-03-01 16:09:17 +01:00
|
|
|
{
|
2023-02-23 14:37:49 +01:00
|
|
|
return updateBoxNode( skinnable, node, Q::TextPanel );
|
2023-03-01 16:09:17 +01:00
|
|
|
}
|
2023-02-19 14:24:09 +01:00
|
|
|
|
|
|
|
case Text:
|
|
|
|
{
|
2023-02-27 09:56:41 +01:00
|
|
|
auto spinBox = static_cast< const QskSpinBox* >( skinnable );
|
|
|
|
|
|
|
|
const auto rect = subControlRect( spinBox, spinBox->contentsRect(), Q::Text );
|
|
|
|
|
|
|
|
return updateTextNode( spinBox, node, rect,
|
|
|
|
spinBox->textAlignment(), spinBox->text(), Q::Text );
|
2023-02-19 14:24:09 +01:00
|
|
|
}
|
2023-02-17 15:22:40 +01:00
|
|
|
}
|
2023-02-19 14:24:09 +01:00
|
|
|
|
2023-02-17 15:22:40 +01:00
|
|
|
return Inherited::updateSubNode( skinnable, nodeRole, node );
|
2023-02-17 12:01:56 +01:00
|
|
|
}
|
2023-02-27 09:56:41 +01:00
|
|
|
|
|
|
|
QRectF QskSpinBoxSkinlet::textPanelRect(
|
|
|
|
const QskSkinnable* skinnable, const QRectF& rect ) const
|
|
|
|
{
|
|
|
|
using Q = QskSpinBox;
|
|
|
|
|
|
|
|
auto spinBox = static_cast< const QskSpinBox* >( skinnable );
|
|
|
|
|
|
|
|
const auto decoration = spinBox->decoration();
|
|
|
|
if ( decoration == Q::NoDecoration )
|
|
|
|
return rect;
|
|
|
|
|
|
|
|
auto r = rect;
|
|
|
|
|
|
|
|
const auto spacing = spinBox->spacingHint( Q::Panel );
|
|
|
|
|
|
|
|
if ( decoration == Q::UpDownControl )
|
|
|
|
{
|
|
|
|
const auto w = subControlRect( skinnable, rect, Q::UpPanel ).width();
|
|
|
|
if ( w > 0.0 )
|
|
|
|
r.setRight( r.right() - spacing - w );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const auto w1 = subControlRect( skinnable, rect, Q::DownPanel ).width();
|
|
|
|
if ( w1 > 0.0 )
|
|
|
|
r.setLeft( r.left() + w1 + spacing );
|
|
|
|
|
|
|
|
const auto w2 = subControlRect( skinnable, rect, Q::UpPanel ).width();
|
|
|
|
if ( w2 > 0.0 )
|
|
|
|
r.setRight( r.right() - w2 - spacing );
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
QRectF QskSpinBoxSkinlet::buttonRect( const QskSkinnable* skinnable,
|
|
|
|
const QRectF& rect, QskAspect::Subcontrol subControl ) const
|
|
|
|
{
|
|
|
|
using Q = QskSpinBox;
|
|
|
|
|
|
|
|
const auto spinBox = static_cast< const QskSpinBox* >( skinnable );
|
|
|
|
|
|
|
|
if ( const auto decoration = spinBox->decoration() )
|
|
|
|
{
|
|
|
|
qreal x, y, w, h;
|
|
|
|
|
2023-02-27 15:21:09 +01:00
|
|
|
if ( decoration == Q::UpDownControl )
|
2023-02-27 09:56:41 +01:00
|
|
|
{
|
|
|
|
const auto hint1 = spinBox->strutSizeHint( Q::UpPanel );
|
|
|
|
const auto hint2 = spinBox->strutSizeHint( Q::DownPanel );
|
|
|
|
|
|
|
|
w = std::max( hint1.width(), hint2.width() );
|
|
|
|
if ( w <= 0 )
|
|
|
|
w = rect.height();
|
|
|
|
|
|
|
|
h = 0.5 * rect.height();
|
|
|
|
|
|
|
|
x = rect.right() - w;
|
|
|
|
y = ( subControl == Q::UpPanel ) ? rect.top() : rect.bottom() - h;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const auto hint = spinBox->strutSizeHint( subControl );
|
|
|
|
|
|
|
|
h = hint.height();
|
|
|
|
if ( h <= 0.0 )
|
|
|
|
h = rect.height();
|
|
|
|
|
|
|
|
w = hint.width();
|
|
|
|
if ( w <= 0.0 )
|
|
|
|
w = h;
|
|
|
|
|
|
|
|
x = ( subControl == Q::UpPanel ) ? rect.right() - w : rect.left();
|
|
|
|
y = 0.5 * ( rect.height() - h );
|
|
|
|
}
|
|
|
|
|
|
|
|
return QRectF( x, y, w, h );
|
|
|
|
}
|
|
|
|
|
|
|
|
return QRectF();
|
|
|
|
}
|
|
|
|
|
|
|
|
QSizeF QskSpinBoxSkinlet::sizeHint( const QskSkinnable* skinnable,
|
|
|
|
Qt::SizeHint which, const QSizeF& ) const
|
|
|
|
{
|
|
|
|
if ( which != Qt::PreferredSize )
|
|
|
|
return QSizeF();
|
|
|
|
|
|
|
|
using Q = QskSpinBox;
|
|
|
|
|
|
|
|
const auto spinBox = static_cast< const QskSpinBox* >( skinnable );
|
|
|
|
|
|
|
|
QSizeF hint;
|
|
|
|
|
|
|
|
{
|
|
|
|
const QFontMetricsF fm( spinBox->effectiveFont( Q::Text ) );
|
|
|
|
|
|
|
|
// 18: QAbstractSpinBox does this
|
|
|
|
const auto w1 = qskHorizontalAdvance( fm,
|
|
|
|
spinBox->textFromValue( spinBox->minimum() ).left( 18 ) );
|
|
|
|
|
|
|
|
const auto w2 = qskHorizontalAdvance( fm,
|
|
|
|
spinBox->textFromValue( spinBox->maximum() ).left( 18 ) );
|
|
|
|
|
|
|
|
hint.setWidth( std::max( w1, w2 ) );
|
|
|
|
hint.setHeight( fm.height() );
|
2023-02-28 15:49:42 +01:00
|
|
|
|
2023-02-27 09:56:41 +01:00
|
|
|
hint = hint.grownBy( spinBox->paddingHint( Q::TextPanel ) );
|
|
|
|
hint = hint.expandedTo( spinBox->strutSizeHint( Q::TextPanel ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( const auto decoration = spinBox->decoration() )
|
|
|
|
{
|
|
|
|
const auto spacing = spinBox->spacingHint( Q::Panel );
|
|
|
|
const auto hintUp = spinBox->strutSizeHint( Q::UpPanel );
|
|
|
|
const auto hintDown = spinBox->strutSizeHint( Q::DownPanel );
|
|
|
|
|
|
|
|
if ( decoration == QskSpinBox::UpDownControl )
|
|
|
|
{
|
|
|
|
qreal w = std::max( hintDown.width(), hintUp.width() );
|
|
|
|
|
|
|
|
qreal h = 0.0;
|
|
|
|
if ( hintDown.height() >= 0.0 )
|
|
|
|
h += hintDown.height();
|
|
|
|
|
|
|
|
if ( hintUp.height() >= 0.0 )
|
|
|
|
h += hintUp.height();
|
|
|
|
|
|
|
|
hint.rwidth() += ( w >= 0.0 ) ? w : hint.height();
|
|
|
|
hint.rwidth() += spacing;
|
|
|
|
|
|
|
|
hint.rheight() = std::max( h, hint.height() );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-02-28 15:49:42 +01:00
|
|
|
if ( hintDown.width() > 0.0 )
|
2023-02-27 09:56:41 +01:00
|
|
|
hint.rwidth() += hintDown.width() + spacing;
|
|
|
|
|
2023-02-28 15:49:42 +01:00
|
|
|
if ( hintUp.width() > 0.0 )
|
2023-02-27 09:56:41 +01:00
|
|
|
hint.rwidth() += hintUp.width() + spacing;
|
|
|
|
|
|
|
|
const auto h = std::max( hintUp.height(), hintDown.height() );
|
|
|
|
hint.rheight() = qMax( h, hint.height() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
hint = hint.expandedTo( spinBox->strutSizeHint( Q::Panel ) );
|
|
|
|
return hint;
|
|
|
|
}
|
2023-03-02 15:13:19 +01:00
|
|
|
|
|
|
|
#include "moc_QskSpinBoxSkinlet.cpp"
|