/****************************************************************************** * QSkinny - Copyright (C) 2016 Uwe Rathmann * This file may be used under the terms of the QSkinny License, Version 1.0 *****************************************************************************/ #include "QskBoxMetrics.h" #include "QskBoxShapeMetrics.h" #include "QskBoxBorderMetrics.h" #include "QskVertex.h" #include "QskFunctions.h" QskBoxMetrics::QskBoxMetrics( const QRectF& rect, const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& border ) : outerRect( rect ) { isOutsideRounded = !shape.isRectangle(); if ( !isOutsideRounded ) { isInsideRounded = false; isOutsideSymmetric = true; stepSymmetries = Qt::Vertical | Qt::Horizontal; preferredOrientation = Qt::Vertical; const auto bw = border.widths(); hasBorder = bw.width() > 0.0 || bw.height() > 0.0; innerRect = qskValidOrEmptyInnerRect( rect, bw ); return; } isOutsideSymmetric = shape.isRectellipse(); { const auto tl = shape.topLeft(); const auto tr = shape.topRight(); const auto bl = shape.bottomLeft(); const auto br = shape.bottomRight(); if ( tl.isEmpty() || tr.isEmpty() || ( tl.height() == tr.height() ) ) { if ( bl.isEmpty() || br.isEmpty() || ( bl.height() == br.height() ) ) stepSymmetries |= Qt::Vertical; } if ( tl.isEmpty() || bl.isEmpty() || ( tl.width() == bl.width() ) ) { if ( tr.isEmpty() || br.isEmpty() || ( tr.width() == br.width() ) ) stepSymmetries |= Qt::Horizontal; } } for ( int i = 0; i < 4; i++ ) { auto& c = corners[ i ]; const auto radius = shape.radius( static_cast< Qt::Corner >( i ) ); c.radiusX = qBound( 0.0, radius.width(), 0.5 * outerRect.width() ); c.radiusY = qBound( 0.0, radius.height(), 0.5 * outerRect.height() ); c.stepCount = QskVertex::ArcIterator::segmentHint( qMax( c.radiusX, c.radiusY ) ); switch ( i ) { case Qt::TopLeftCorner: c.centerX = outerRect.left() + c.radiusX; c.centerY = outerRect.top() + c.radiusY; c.sx = -1.0; c.sy = -1.0; break; case Qt::TopRightCorner: c.centerX = outerRect.right() - c.radiusX; c.centerY = outerRect.top() + c.radiusY; c.sx = +1.0; c.sy = -1.0; break; case Qt::BottomLeftCorner: c.centerX = outerRect.left() + c.radiusX; c.centerY = outerRect.bottom() - c.radiusY; c.sx = -1.0; c.sy = +1.0; break; case Qt::BottomRightCorner: c.centerX = outerRect.right() - c.radiusX; c.centerY = outerRect.bottom() - c.radiusY; c.sx = +1.0; c.sy = +1.0; break; } } { const auto cleft = qMax( corners[ Qt::TopLeftCorner ].centerX, corners[ Qt::BottomLeftCorner ].centerX ); const auto cright = qMin( corners[ Qt::TopRightCorner ].centerX, corners[ Qt::BottomRightCorner ].centerX ); const auto ctop = qMax( corners[ Qt::TopLeftCorner ].centerY, corners[ Qt::TopRightCorner ].centerY ); const auto cbottom = qMin( corners[ Qt::BottomLeftCorner ].centerY, corners[ Qt::BottomRightCorner ].centerY ); // now the bounding rectangle of the fill area const auto bw = border.widths(); hasBorder = bw.width() > 0.0 || bw.height() > 0.0; qreal l = outerRect.left() + bw.left(); qreal t = outerRect.top() + bw.top(); qreal r = outerRect.right() - bw.right(); qreal b = outerRect.bottom() - bw.bottom(); l = qMin( l, cright ); r = qMax( r, cleft ); t = qMin( t, cbottom ); b = qMax( b, ctop ); if ( l > r ) l = r = r + 0.5 * ( l - r ); if ( t > b ) t = b = b + 0.5 * ( t - b ); innerRect.setCoords( l, t, r, b ); } const QskMargins margins( innerRect.left() - outerRect.left(), innerRect.top() - outerRect.top(), outerRect.right() - innerRect.right(), outerRect.bottom() - innerRect.bottom() ); isBorderRegular = margins.isEquidistant(); isInsideRounded = false; for ( int i = 0; i < 4; i++ ) { auto& c = corners[ i ]; if ( c.sx < 0.0 ) c.radiusInnerX = c.radiusX - margins.left(); else c.radiusInnerX = c.radiusX - margins.right(); if ( c.sy < 0.0 ) c.radiusInnerY = c.radiusY - margins.top(); else c.radiusInnerY = c.radiusY - margins.bottom(); if ( c.radiusInnerX > 0.0 && c.radiusInnerY > 0.0 ) { c.centerInnerX = c.centerX; c.centerInnerY = c.centerY; isInsideRounded = true; } else { /* not enough space for a rounded border -> the inner side becomes rectangular */ c.radiusInnerX = c.radiusInnerY = 0.0; c.centerInnerX = ( c.sx < 0.0 ) ? innerRect.left() : innerRect.right(); c.centerInnerY = ( c.sy < 0.0 ) ? innerRect.top() : innerRect.bottom(); } } { const auto tl = corners[ Qt::TopLeftCorner ].innerStepCount(); const auto tr = corners[ Qt::TopRightCorner ].innerStepCount(); const auto bl = corners[ Qt::BottomLeftCorner ].innerStepCount(); const auto br = corners[ Qt::BottomRightCorner ].innerStepCount(); if ( qMax( tl, tr ) + qMax( bl, br ) >= qMax( tl, bl ) + qMax( tr, br ) ) preferredOrientation = Qt::Vertical; else preferredOrientation = Qt::Horizontal; } } int QskBoxMetrics::outerStepCount() const { return corners[0].stepCount + corners[1].stepCount + corners[2].stepCount + corners[3].stepCount; } int QskBoxMetrics::innerStepCount() const { return corners[0].innerStepCount() + corners[1].innerStepCount() + corners[2].innerStepCount() + corners[3].innerStepCount(); }