/****************************************************************************** * QSkinny - Copyright (C) 2016 Uwe Rathmann * This file may be used under the terms of the QSkinny License, Version 1.0 *****************************************************************************/ #include "QskStatusIndicator.h" #include "QskGraphic.h" #include "QskColorFilter.h" #include "QskGraphicProvider.h" #include QSK_SUBCONTROL( QskStatusIndicator, Graphic ) namespace { class StatusData { public: StatusData( const QskGraphic& graphic ): graphic( graphic ), isDirty( false ) { } StatusData( const QUrl& url ): source( url ), isDirty( !url.isEmpty() ) { } void ensureGraphic( const QskStatusIndicator* indicator ) { if ( !source.isEmpty() && isDirty ) { graphic = indicator->loadSource( source ); isDirty = false; } } QUrl source; QskGraphic graphic; bool isDirty : 1; }; } class QskStatusIndicator::PrivateData { public: PrivateData(): currentStatus( -1 ) { } int currentStatus; QMap< int, StatusData > map; }; QskStatusIndicator::QskStatusIndicator( QQuickItem* parent ): Inherited( parent ), m_data( new PrivateData() ) { initSizePolicy( QskSizePolicy::Expanding, QskSizePolicy::Expanding ); } QskStatusIndicator::~QskStatusIndicator() { } QUrl QskStatusIndicator::source( int status ) const { const auto it = m_data->map.find( status ); if ( it != m_data->map.end() ) return it->source; return QUrl(); } void QskStatusIndicator::setSource( int status, const QUrl& url ) { bool hasChanged = false; const auto it = m_data->map.find( status ); if ( it != m_data->map.end() ) { if ( it->source != url ) { it->source = url; it->graphic.reset(); it->isDirty = !url.isEmpty(); hasChanged = true; } } else { m_data->map.insert( status, StatusData( url ) ); hasChanged = true; } if ( hasChanged ) { resetImplicitSize(); if ( status == m_data->currentStatus ) update(); } } QskGraphic QskStatusIndicator::graphic( int status ) const { const auto it = m_data->map.find( status ); if ( it != m_data->map.end() ) return it->graphic; return QskGraphic(); } void QskStatusIndicator::setGraphic( int status, const QskGraphic& graphic ) { bool hasChanged = false; const auto it = m_data->map.find( status ); if ( it != m_data->map.end() ) { if ( !it->source.isEmpty() || graphic != it->graphic ) { it->source.clear(); it->isDirty = false; it->graphic = graphic; hasChanged = true; } } else { m_data->map.insert( status, StatusData( graphic ) ); hasChanged = true; } if ( hasChanged ) { resetImplicitSize(); if ( status == m_data->currentStatus ) update(); } } QskColorFilter QskStatusIndicator::graphicFilter( int status ) const { Q_UNUSED( status ) return effectiveGraphicFilter( QskStatusIndicator::Graphic ); } qreal QskStatusIndicator::heightForWidth( qreal width ) const { return sizeConstraint( Qt::Horizontal, width ); } qreal QskStatusIndicator::widthForHeight( qreal height ) const { return sizeConstraint( Qt::Vertical, height ); } qreal QskStatusIndicator::sizeConstraint( Qt::Orientation orientation, qreal constraint ) const { if ( constraint <= 0.0 ) return 0.0; qreal value = 0.0; for ( auto &statusData : m_data->map ) { statusData.ensureGraphic( this ); if ( !statusData.graphic.isEmpty() ) { const QSizeF sz = statusData.graphic.defaultSize(); if ( !sz.isEmpty() ) { qreal v; if ( orientation == Qt::Horizontal ) v = sz.height() * constraint / sz.width(); else v = sz.width() * constraint / sz.height(); if ( v > value ) value = v; } } } return value; } QSizeF QskStatusIndicator::contentsSizeHint() const { QSizeF sz( 0, 0 ); for ( auto &statusData : m_data->map ) { statusData.ensureGraphic( this ); if ( !statusData.graphic.isEmpty() ) sz = sz.expandedTo( statusData.graphic.defaultSize() ); } return sz; } int QskStatusIndicator::status() const { return m_data->currentStatus; } bool QskStatusIndicator::hasStatus( int status ) const { return m_data->map.contains( status ); } void QskStatusIndicator::setStatus( int status ) { if ( status == m_data->currentStatus ) return; const auto it = m_data->map.constFind( status ); if ( it == m_data->map.constEnd() ) { qWarning() << "QskStatusIndicator: invalid status:" << status; return; } m_data->currentStatus = status; Q_EMIT statusChanged( m_data->currentStatus ); // we should have a mode to decide if we // want to keep the hidden graphics in memory if ( it->isDirty ) polish(); update(); } void QskStatusIndicator::changeEvent( QEvent* event ) { if ( event->type() == QEvent::StyleChange ) { for ( auto &statusData : m_data->map ) { if ( !statusData.source.isEmpty() ) { statusData.graphic.reset(); statusData.isDirty = true; } } } Inherited::changeEvent( event ); } void QskStatusIndicator::updateLayout() { const auto it = m_data->map.find( m_data->currentStatus ); if ( it != m_data->map.end() ) it->ensureGraphic( this ); } QskGraphic QskStatusIndicator::loadSource( const QUrl& url ) const { return Qsk::loadGraphic( url ); } #include "moc_QskStatusIndicator.cpp"