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

View File

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

View File

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

View File

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

View File

@ -57,6 +57,21 @@ int main( int argc, char* argv[] )
QskGraphic graphic; 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 ); QPainter painter( &graphic );
renderer.render( &painter ); renderer.render( &painter );
painter.end(); painter.end();