QskGraphic::defaultSize replaced by QskGraphic::viewBox. svg2qvg uses

the viewBox of the SVG document to initialize the viewBox of the
graphic. Avoids scaling problems with the symbols of the skins, that
often rely on having a viewBox.
This commit is contained in:
Uwe Rathmann 2024-04-17 14:46:29 +02:00
parent 15118cfe07
commit c78c0f03a1
47 changed files with 173 additions and 61 deletions

View File

@ -0,0 +1,15 @@
#! /bin/sh
if [ $# -eq 0 ]; then
echo "Usage $0 file ..."
exit 1
fi
for file in $*
do
base=`basename -s .svg $file`
echo "${base}.svg -> qvg/${base}.qvg"
svg2qvg ${base}.svg qvg/${base}.qvg
done
exit $status

View File

@ -145,13 +145,21 @@ namespace
if ( strcmp( name, "checkMark" ) == 0 )
{
graphic.setViewBox( QRectF( 0.0, 0.0, 14.0, 14.0 ) );
QPainterPath path;
path.moveTo( 0.11, 0.47 );
path.lineTo( 0.5, 1.0);
path.lineTo( 1.0, 0.0 );
path.moveTo( 3.5, 7.0 );
path.lineTo( 6.5, 14.0 );
path.lineTo( 11.0, 1.0 );
QPen pen( Qt::black, 2.8 );
pen.setCapStyle( Qt::FlatCap );
pen.setJoinStyle( Qt::BevelJoin );
QPainter painter( &graphic );
painter.setPen( QPen( Qt::black, 0.25 ) );
painter.setRenderHint( QPainter::Antialiasing );
painter.setPen( pen );
painter.drawPath( path );
}
@ -209,19 +217,12 @@ void Editor::setupCheckBox()
}
}
setGraphicRole( Q::Indicator, QskFusionSkin::GraphicNormal );
setGraphicRole( Q::Indicator, QskFusionSkin::GraphicIndicator );
setGraphicRole( Q::Indicator | Q::Disabled, QskFusionSkin::GraphicDisabled );
setGraphicRole( Q::Indicator | Q::Error, QskFusionSkin::GraphicError );
#if 0
// aligning/scaling of the symbols needs to be fixed in the skinlet TODO ..
setPadding( Q::Box, 4_dp );
setPadding( Q::Box, 3_dp );
const auto checkMark = symbol( "checkMark" );
#else
setPadding( Q::Box, 2_dp );
const auto checkMark = QskStandardSymbol::graphic( QskStandardSymbol::CheckMark );
#endif
for ( auto state : { QskAspect::NoState, Q::Disabled } )
{
@ -277,6 +278,7 @@ void Editor::setupComboBox()
setGraphicRole( Q::Icon | Q::Disabled, QskFusionSkin::GraphicDisabled );
setStrutSize( Q::StatusIndicator, 10_dp, 10_dp );
setGraphicRole( Q::StatusIndicator, QskFusionSkin::GraphicIndicator );
setGraphicRole( Q::StatusIndicator | Q::Disabled, QskFusionSkin::GraphicDisabled );
setAlignment( Q::StatusIndicator, Qt::AlignRight | Qt::AlignVCenter );
@ -1339,6 +1341,13 @@ void QskFusionSkin::initHints()
setGraphicColor( GraphicError, palette.error );
setGraphicColor( GraphicHighlighted, palette.active( P::HighlightedText ) );
{
auto rgb = palette.darker( P::Active, P::Text, 120 );
rgb = QskRgb::toTransparent( rgb, 180 );
setGraphicColor( GraphicIndicator, rgb );
}
Editor editor( palette, &hintTable() );
editor.setup();
}

View File

@ -24,7 +24,8 @@ class QSK_FUSION_EXPORT QskFusionSkin : public QskSkin
GraphicNormal,
GraphicDisabled,
GraphicHighlighted,
GraphicError
GraphicError,
GraphicIndicator
};
protected:

View File

@ -0,0 +1,15 @@
#! /bin/sh
if [ $# -eq 0 ]; then
echo "Usage $0 file ..."
exit 1
fi
for file in $*
do
base=`basename -s .svg $file`
echo "${base}.svg -> qvg/${base}.qvg"
svg2qvg ${base}.svg qvg/${base}.qvg
done
exit $status

View File

@ -0,0 +1,15 @@
#! /bin/sh
if [ $# -eq 0 ]; then
echo "Usage $0 file ..."
exit 1
fi
for file in $*
do
base=`basename -s .svg $file`
echo "${base}.svg -> qvg/${base}.qvg"
svg2qvg ${base}.svg qvg/${base}.qvg
done
exit $status

Binary file not shown.

View File

@ -0,0 +1,15 @@
#! /bin/sh
if [ $# -eq 0 ]; then
echo "Usage $0 file ..."
exit 1
fi
for file in $*
do
base=`basename -s .svg $file`
echo "${base}.svg -> qvg/${base}.qvg"
svg2qvg ${base}.svg qvg/${base}.qvg
done
exit $status

Binary file not shown.

View File

@ -339,7 +339,7 @@ class QskGraphic::PrivateData : public QSharedData
PrivateData( const PrivateData& other )
: QSharedData( other )
, defaultSize( other.defaultSize )
, viewBox( other.viewBox )
, commands( other.commands )
, pathInfos( other.pathInfos )
, boundingRect( other.boundingRect )
@ -354,7 +354,18 @@ class QskGraphic::PrivateData : public QSharedData
{
return ( modificationId == other.modificationId ) &&
( renderHints == other.renderHints ) &&
( defaultSize == other.defaultSize );
( viewBox == other.viewBox );
}
void resetCommands()
{
commands.clear();
pathInfos.clear();
commandTypes = 0;
boundingRect = pointRect = { 0.0, 0.0, -1.0, -1.0 };
modificationId = 0;
}
inline void addCommand( const QskPainterCommand& command )
@ -365,7 +376,7 @@ class QskGraphic::PrivateData : public QSharedData
modificationId = nextId.fetchAndAddRelaxed( 1 );
}
QSizeF defaultSize;
QRectF viewBox = { 0.0, 0.0, -1.0, -1.0 };
QVector< QskPainterCommand > commands;
QVector< QskGraphicPrivate::PathInfo > pathInfos;
@ -492,16 +503,9 @@ int QskGraphic::metric( PaintDeviceMetric deviceMetric ) const
void QskGraphic::reset()
{
m_data->commands.clear();
m_data->pathInfos.clear();
m_data->resetCommands();
m_data->commandTypes = 0;
m_data->boundingRect = QRectF( 0.0, 0.0, -1.0, -1.0 );
m_data->pointRect = QRectF( 0.0, 0.0, -1.0, -1.0 );
m_data->defaultSize = QSizeF();
m_data->modificationId = 0;
m_data->viewBox = { 0.0, 0.0, -1.0, -1.0 };
delete m_paintEngine;
m_paintEngine = nullptr;
@ -580,18 +584,20 @@ QSize QskGraphic::sizeMetrics() const
return QSize( qCeil( sz.width() ), qCeil( sz.height() ) );
}
void QskGraphic::setDefaultSize( const QSizeF& size )
void QskGraphic::setViewBox( const QRectF& rect )
{
const double w = qMax( qreal( 0.0 ), size.width() );
const double h = qMax( qreal( 0.0 ), size.height() );
m_data->viewBox = rect;
}
m_data->defaultSize = QSizeF( w, h );
QRectF QskGraphic::viewBox() const
{
return m_data->viewBox;
}
QSizeF QskGraphic::defaultSize() const
{
if ( !m_data->defaultSize.isEmpty() )
return m_data->defaultSize;
if ( !m_data->viewBox.isEmpty() )
return m_data->viewBox.size();
return boundingRect().size();
}
@ -670,30 +676,42 @@ void QskGraphic::render( QPainter* painter, const QRectF& rect,
if ( isEmpty() || rect.isEmpty() )
return;
const bool scalePens = !( m_data->renderHints & RenderPensUnscaled );
qreal sx = 1.0;
qreal sy = 1.0;
if ( m_data->pointRect.width() > 0.0 )
sx = rect.width() / m_data->pointRect.width();
QRectF boundingBox = m_data->viewBox;
if ( m_data->pointRect.height() > 0.0 )
sy = rect.height() / m_data->pointRect.height();
const bool scalePens = !( m_data->renderHints & RenderPensUnscaled );
for ( const auto& info : std::as_const( m_data->pathInfos ) )
if ( !boundingBox.isEmpty() )
{
const qreal ssx = info.scaleFactorX( m_data->pointRect,
rect, m_data->boundingRect, scalePens );
sx = rect.width() / boundingBox.width();
sy = rect.height() / boundingBox.height();
}
else
{
boundingBox = m_data->boundingRect;
if ( ssx > 0.0 )
sx = qMin( sx, ssx );
if ( m_data->pointRect.width() > 0.0 )
sx = rect.width() / m_data->pointRect.width();
const qreal ssy = info.scaleFactorY( m_data->pointRect,
rect, m_data->boundingRect, scalePens );
if ( m_data->pointRect.height() > 0.0 )
sy = rect.height() / m_data->pointRect.height();
if ( ssy > 0.0 )
sy = qMin( sy, ssy );
for ( const auto& info : std::as_const( m_data->pathInfos ) )
{
const qreal ssx = info.scaleFactorX( m_data->pointRect,
rect, m_data->boundingRect, scalePens );
if ( ssx > 0.0 )
sx = qMin( sx, ssx );
const qreal ssy = info.scaleFactorY( m_data->pointRect,
rect, m_data->boundingRect, scalePens );
if ( ssy > 0.0 )
sy = qMin( sy, ssy );
}
}
if ( aspectRatioMode == Qt::KeepAspectRatio )
@ -705,15 +723,17 @@ void QskGraphic::render( QPainter* painter, const QRectF& rect,
sx = sy = qMax( sx, sy );
}
const auto& br = m_data->boundingRect;
const auto rc = rect.center();
QTransform tr;
tr.translate(
rc.x() - 0.5 * sx * br.width(),
rc.y() - 0.5 * sy * br.height() );
tr.scale( sx, sy );
tr.translate( -br.x(), -br.y() );
{
const auto rc = rect.center();
tr.translate(
rc.x() - 0.5 * sx * boundingBox.width(),
rc.y() - 0.5 * sy * boundingBox.height() );
tr.scale( sx, sy );
tr.translate( -boundingBox.x(), -boundingBox.y() );
}
const auto transform = painter->transform();
@ -986,7 +1006,7 @@ const QVector< QskPainterCommand >& QskGraphic::commands() const
void QskGraphic::setCommands( const QVector< QskPainterCommand >& commands )
{
reset();
m_data->resetCommands();
const int numCommands = commands.size();
if ( numCommands <= 0 )
@ -1019,9 +1039,7 @@ quint64 QskGraphic::modificationId() const
QskHashValue QskGraphic::hash( QskHashValue seed ) const
{
auto hash = qHash( m_data->renderHints, seed );
hash = qHash( m_data->defaultSize.width(), hash );
hash = qHash( m_data->defaultSize.height(), hash );
hash = qHashBits( &m_data->viewBox, sizeof( QRectF ), hash );
return qHash( m_data->modificationId, hash );
}

View File

@ -29,6 +29,7 @@ class QSK_EXPORT QskGraphic : public QPaintDevice
Q_GADGET
Q_PROPERTY( qreal aspectRatio READ aspectRatio )
Q_PROPERTY( QRectF viewBox READ viewBox WRITE setViewBox )
Q_PROPERTY( QRectF boundingRect READ boundingRect )
Q_PROPERTY( QRectF controlPointRect READ controlPointRect )
Q_PROPERTY( QSizeF defaultSize READ defaultSize )
@ -106,9 +107,11 @@ class QSK_EXPORT QskGraphic : public QPaintDevice
const QVector< QskPainterCommand >& commands() const;
void setCommands( const QVector< QskPainterCommand >& );
void setDefaultSize( const QSizeF& );
QSizeF defaultSize() const;
void setViewBox( const QRectF& );
QRectF viewBox() const;
qreal aspectRatio() const;
qreal heightForWidth( qreal width ) const;

View File

@ -241,6 +241,9 @@ QskGraphic QskGraphicIO::read( QIODevice* dev )
return QskGraphic();
}
QRectF viewBox;
stream >> viewBox;
quint32 numCommands;
stream >> numCommands;
@ -280,6 +283,7 @@ QskGraphic QskGraphicIO::read( QIODevice* dev )
}
QskGraphic graphic;
graphic.setViewBox( viewBox );
graphic.setCommands( commands );
return graphic;
@ -315,6 +319,8 @@ bool QskGraphicIO::write( const QskGraphic& graphic, QIODevice* dev )
stream.setByteOrder( QDataStream::BigEndian );
stream.writeRawData( qskMagicNumber, 4 );
stream << graphic.viewBox();
const auto numCommands = graphic.commands().size();
const QskPainterCommand* cmds = graphic.commands().constData();

View File

@ -57,6 +57,21 @@ int main( int argc, char* argv[] )
QskGraphic graphic;
{
/*
QSvgRenderer::viewBoxF() returns a bounding box when no viewBox
has been defined. So we clear the viewBox and compare the result with
the initial value - assuming, that there was a viewBox when they differ.
*/
const auto viewBox = renderer.viewBoxF();
renderer.setViewBox( QRectF() );
if ( viewBox != renderer.viewBoxF() )
graphic.setViewBox( viewBox );
}
QPainter painter( &graphic );
renderer.render( &painter );
painter.end();