diff options
Diffstat (limited to 'tests/manual/svg')
30 files changed, 1186 insertions, 0 deletions
diff --git a/tests/manual/svg/CMakeLists.txt b/tests/manual/svg/CMakeLists.txt new file mode 100644 index 0000000000..1576c0d741 --- /dev/null +++ b/tests/manual/svg/CMakeLists.txt @@ -0,0 +1,74 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.5) + +project(svg VERSION 0.1 LANGUAGES CXX) + +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Quick Qml Svg SvgWidgets QuickWidgets QuickVectorImageGeneratorPrivate) +find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Quick Qml Svg SvgWidgets QuickWidgets QuickVectorImageGeneratorPrivate) + +set(PROJECT_SOURCES + main.cpp + mainwindow.h mainwindow.cpp + mainwindow.ui + svgpainter.h svgpainter.cpp + svgmanager.h svgmanager.cpp +) + +if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) + qt_add_executable(svg + MANUAL_FINALIZATION + ${PROJECT_SOURCES} + ) +# Define target properties for Android with Qt 6 as: +# set_property(TARGET svg APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR +# ${CMAKE_CURRENT_SOURCE_DIR}/android) +# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation +else() + if(ANDROID) + add_library(svg SHARED + ${PROJECT_SOURCES} + ) +# Define properties for Android with Qt 5 after find_package() calls as: +# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android") + else() + add_executable(svg + ${PROJECT_SOURCES} + ) + endif() +endif() + +target_link_libraries(svg PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Quick Qt${QT_VERSION_MAJOR}::Qml Qt${QT_VERSION_MAJOR}::Svg Qt${QT_VERSION_MAJOR}::QuickWidgets Qt${QT_VERSION_MAJOR}::QuickVectorImageGeneratorPrivate Qt${QT_VERSION_MAJOR}::SvgWidgets) + +set_target_properties(svg PROPERTIES + MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com + MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} + MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + MACOSX_BUNDLE TRUE + WIN32_EXECUTABLE TRUE +) + +install(TARGETS svg + BUNDLE DESTINATION . + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) + +qt_add_qml_module(svg + VERSION 1.0 + URI SvgImageTest + QML_FILES SvgImage.qml QmlGenerator.qml +) + + +if(QT_VERSION_MAJOR EQUAL 6) + qt_finalize_executable(svg) +endif() diff --git a/tests/manual/svg/QmlGenerator.qml b/tests/manual/svg/QmlGenerator.qml new file mode 100644 index 0000000000..96435ba4f0 --- /dev/null +++ b/tests/manual/svg/QmlGenerator.qml @@ -0,0 +1,26 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +import QtQuick +import SvgImageTest + +Item { + id: item + width: childrenRect.width * (SvgManager.scale / 10.0) + height: childrenRect.height * (SvgManager.scale / 10.0) + scale: SvgManager.scale / 10 + transformOrigin: Item.TopLeft + + property var dynamicObject: null + Connections { + target: SvgManager + function onCurrentSourceChanged() { + if (dynamicObject) + dynamicObject.destroy() + + var s = SvgManager.qmlSource + + dynamicObject = Qt.createQmlObject(s, item, "dummy.qml") + } + } +} diff --git a/tests/manual/svg/SvgImage.qml b/tests/manual/svg/SvgImage.qml new file mode 100644 index 0000000000..ce0bb4ab12 --- /dev/null +++ b/tests/manual/svg/SvgImage.qml @@ -0,0 +1,17 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +import QtQuick +import QtQuick.VectorImage +import SvgImageTest + +Item { + width: vectorImage.implicitWidth * (SvgManager.scale / 10.0) + height: vectorImage.implicitHeight * (SvgManager.scale / 10.0) + scale: SvgManager.scale / 10.0 + transformOrigin: Item.TopLeft + VectorImage { + id: vectorImage + source: SvgManager.currentSource + } +} diff --git a/tests/manual/svg/data/image/1.svg b/tests/manual/svg/data/image/1.svg new file mode 100644 index 0000000000..d5f27450c2 --- /dev/null +++ b/tests/manual/svg/data/image/1.svg @@ -0,0 +1,3 @@ +<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg"> + <image xlink:href="data.png" height="200" width="200" /> +</svg> diff --git a/tests/manual/svg/data/image/2.svg b/tests/manual/svg/data/image/2.svg new file mode 100644 index 0000000000..3f71e5ca23 --- /dev/null +++ b/tests/manual/svg/data/image/2.svg @@ -0,0 +1,3 @@ +<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg"> + <image xlink:href="qtlogo.png" height="200" width="200" /> +</svg> diff --git a/tests/manual/svg/data/image/3.svg b/tests/manual/svg/data/image/3.svg new file mode 100644 index 0000000000..85751587d9 --- /dev/null +++ b/tests/manual/svg/data/image/3.svg @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg viewBox="0 0 210 297"> +<image width="200" height="200" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFQAAAA8CAYAAAGPy61gAAAAAXNSR0IArs4c6QAAAJZlWElmTU0A KgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgExAAIAAAARAAAAWodp AAQAAAABAAAAbAAAAAAAAABIAAAAAQAAAEgAAAABQWRvYmUgSW1hZ2VSZWFkeQAAAAOgAQADAAAA AQABAACgAgAEAAAAAQAAAFSgAwAEAAAAAQAAADwAAAAAm/SbDAAAAAlwSFlzAAALEwAACxMBAJqc GAAAAi1pVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6 bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDYuMC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRm PSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJk ZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6eG1wPSJodHRwOi8v bnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMu YWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx4bXA6Q3JlYXRvclRvb2w+QWRvYmUgSW1h Z2VSZWFkeTwveG1wOkNyZWF0b3JUb29sPgogICAgICAgICA8dGlmZjpZUmVzb2x1dGlvbj43Mjwv dGlmZjpZUmVzb2x1dGlvbj4KICAgICAgICAgPHRpZmY6T3JpZW50YXRpb24+MTwvdGlmZjpPcmll bnRhdGlvbj4KICAgICAgICAgPHRpZmY6WFJlc29sdXRpb24+NzI8L3RpZmY6WFJlc29sdXRpb24+ CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgpg60/Z AAAXv0lEQVR4Ae1caZBdxXXuvve+bXaNFhAIJI0EWmZGCEaIJYVLBlxFlkpBbBGXKwRXYkOFwmAW B20uPYFGQrahAnHiiMTlCrHLCYqdhB/g2NiocDDgMEbSLEhCmhkJAVJmkWZ9672d7+v77tvfmzej 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 rkJggg== " id="image1" x="10" y="10" /> +</svg> diff --git a/tests/manual/svg/data/image/data.png b/tests/manual/svg/data/image/data.png Binary files differnew file mode 100644 index 0000000000..7b660be3de --- /dev/null +++ b/tests/manual/svg/data/image/data.png diff --git a/tests/manual/svg/data/image/qtlogo.png b/tests/manual/svg/data/image/qtlogo.png Binary files differnew file mode 100644 index 0000000000..7b660be3de --- /dev/null +++ b/tests/manual/svg/data/image/qtlogo.png diff --git a/tests/manual/svg/data/painting/fill_color.svg b/tests/manual/svg/data/painting/fill_color.svg new file mode 100644 index 0000000000..7772839369 --- /dev/null +++ b/tests/manual/svg/data/painting/fill_color.svg @@ -0,0 +1,7 @@ +<svg viewBox="0 0 400 1000" xmlns="http://www.w3.org/2000/svg"> + <g fill-opacity="0.3"> + <rect width="300" height="300" fill="red"/> + </g> + <rect transform="translate(0, 350)" width="300" height="300" fill="red"/> + <rect transform="translate(0, 700)" width="300" height="300" fill="transparent" stroke="yellow" stroke-width="5"/> +</svg> diff --git a/tests/manual/svg/data/painting/fill_gradient.svg b/tests/manual/svg/data/painting/fill_gradient.svg new file mode 100644 index 0000000000..5fefb40442 --- /dev/null +++ b/tests/manual/svg/data/painting/fill_gradient.svg @@ -0,0 +1,15 @@ +<svg viewBox="0 0 200 400" xmlns="http://www.w3.org/2000/svg"> + <defs> + <linearGradient id="grad1" x1="0%" x2="100%" y1="0%" y2="0%"> + <stop offset="0%" stop-color="green" stop-opacity="0.8"/> + <stop offset="100%" stop-color="red" stop-opacity="0.8"/> + </linearGradient> + <linearGradient id="grad2" x1="0%" x2="100%" y1="0%" y2="0%"> + <stop offset="0%" stop-color="green"/> + <stop offset="100%" stop-color="red"/> + </linearGradient> + </defs> + <ellipse cx="100" cy="70" rx="85" ry="55" fill="url(#grad1)"/> + <ellipse cx="100" cy="200" rx="85" ry="55" fill="url(#grad2)" fill-opacity="0.8"/> + <ellipse cx="100" cy="330" rx="85" ry="55" fill="url(#grad1)" fill-opacity="0.5"/> +</svg> diff --git a/tests/manual/svg/data/painting/fill_stroke.svg b/tests/manual/svg/data/painting/fill_stroke.svg new file mode 100644 index 0000000000..8069faf516 --- /dev/null +++ b/tests/manual/svg/data/painting/fill_stroke.svg @@ -0,0 +1,3 @@ +<svg viewBox="0 0 800 800" xmlns="http://www.w3.org/2000/svg"> + <rect transform="translate(50, 50)" width="400" height="400" fill="green" stroke="black" fill-opacity="0.5" stroke-opacity="0.2" stroke-width="20"/> +</svg>
\ No newline at end of file diff --git a/tests/manual/svg/data/painting/stroke_color.svg b/tests/manual/svg/data/painting/stroke_color.svg new file mode 100644 index 0000000000..d77755e1fd --- /dev/null +++ b/tests/manual/svg/data/painting/stroke_color.svg @@ -0,0 +1,7 @@ +<svg viewBox="0 0 400 1000" xmlns="http://www.w3.org/2000/svg"> + <g stroke-opacity="0.3"> + <rect transform="translate(25, 25)" width="300" height="300" stroke="red" stroke-width="10"/> + </g> + <rect transform="translate(25, 350)" width="300" height="300" stroke="red" stroke-width="10"/> + <rect transform="translate(25, 700)" width="300" height="300" fill="yellow" stroke="transparent"/> +</svg> diff --git a/tests/manual/svg/data/styling/stroking_capStyle_shapes_1.svg b/tests/manual/svg/data/styling/stroking_capStyle_shapes_1.svg new file mode 100644 index 0000000000..9448fcb527 --- /dev/null +++ b/tests/manual/svg/data/styling/stroking_capStyle_shapes_1.svg @@ -0,0 +1,11 @@ +<svg width="900" height="600" viewBox="0 0 90 60" xmlns="http://www.w3.org/2000/svg"> + <defs> + <g id="capTest"> + <polyline points="10,10 80,10" fill="none" stroke-width="8" stroke="black"/> + <polyline points="10,10 80,10" fill="none" stroke-width="0.5" stroke-linecap="butt" stroke="yellow"/> + </g> + </defs> + <use href="#capTest" stroke-linecap="butt"/> + <use href="#capTest" y="20" stroke-linecap="round"/> + <use href="#capTest" y=" 40" stroke-linecap="square"/> +</svg> diff --git a/tests/manual/svg/data/styling/stroking_capStyle_shapes_2.svg b/tests/manual/svg/data/styling/stroking_capStyle_shapes_2.svg new file mode 100644 index 0000000000..1d52d2d247 --- /dev/null +++ b/tests/manual/svg/data/styling/stroking_capStyle_shapes_2.svg @@ -0,0 +1,12 @@ +<svg width="900" height="300" viewBox="0 0 130 40" xmlns="http://www.w3.org/2000/svg"> + <defs> + <polyline id="letterz" points="10,10 40,10 10,30 40,30" fill="none" stroke-width="2.5" stroke="black"/> + <polyline id="highlight" points="10,10 40,10 10,30 40,30" fill="none" stroke-width="0.1" stroke="yellow"/> + </defs> + <use href="#letterz" stroke-linecap="butt"/> + <use href="#highlight"/> + <use href="#letterz" x="40" stroke-linecap="round"/> + <use href="#highlight" x="40"/> + <use href="#letterz" x=" 80" stroke-linecap="square"/> + <use href="#highlight" x="80"/> +</svg> diff --git a/tests/manual/svg/data/styling/stroking_dash.svg b/tests/manual/svg/data/styling/stroking_dash.svg new file mode 100644 index 0000000000..5fdefa4cce --- /dev/null +++ b/tests/manual/svg/data/styling/stroking_dash.svg @@ -0,0 +1,10 @@ +<svg width="460" height="200" viewBox="0 0 30 13" xmlns="http://www.w3.org/2000/svg"> + <line x1="0" y1="1" x2="30" y2="1" stroke="black" stroke-dashoffset="2"/> + <line x1="0" y1="3" x2="30" y2="3" stroke="black" stroke-dasharray="4 2"/> +<!--positive dashoffset pulls the dashes--> + <line x1="0" y1="5" x2="30" y2="5" stroke="black" stroke-dasharray="4 2" stroke-dashoffset="2"/> + <line x1="0" y1="7" x2="30" y2="7" stroke="black" stroke-dasharray="4 2" stroke-dashoffset="4"/> + <!--negative dashoffset pushs the dashes--> + <line x1="0" y1="9" x2="30" y2="9" stroke="black" stroke-dasharray="4 2" stroke-dashoffset="-2"/> + <line x1="0" y1="11" x2="30" y2="11" stroke="black" stroke-dasharray="4 2" stroke-dashoffset="-4"/> +</svg> diff --git a/tests/manual/svg/data/styling/stroking_joinStyle_shapes_1.svg b/tests/manual/svg/data/styling/stroking_joinStyle_shapes_1.svg new file mode 100644 index 0000000000..1da775a97e --- /dev/null +++ b/tests/manual/svg/data/styling/stroking_joinStyle_shapes_1.svg @@ -0,0 +1,12 @@ +<svg width="600" height="200" viewBox="0 0 30 10" xmlns="http://www.w3.org/2000/svg"> + <defs> + <g id="capTest"> + <polyline points="1,8 1,2 7,2" fill="none" stroke-width="1" stroke="black"/> + <polyline points="1,8 1,2 7,2" fill="none" stroke-width="0.03" stroke="yellow"/> + </g> + </defs> + + <use href="#capTest" x="1" stroke-linejoin="bevel"/> + <use href="#capTest" x="11" stroke-linejoin="round"/> + <use href="#capTest" x="21" stroke-linejoin="miter"/> +</svg> diff --git a/tests/manual/svg/data/styling/stroking_text.svg b/tests/manual/svg/data/styling/stroking_text.svg new file mode 100644 index 0000000000..bacc04fff4 --- /dev/null +++ b/tests/manual/svg/data/styling/stroking_text.svg @@ -0,0 +1,4 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="250" height="200"> + <text y="70" style="font-size: 80px; font-weight: bold; font-family: sans-serif; stroke-dasharray:5,5; fill: peachpuff; stroke: crimson; stroke-width:4.1px; stroke-linecap: square; stroke-linejoin: bevel;">pizazz</text> + <text y="150" style="font-size: 80px; font-weight: bold; font-family: sans-serif; fill: peachpuff; stroke: blue; stroke-width:4.1px; stroke-linecap: square; stroke-linejoin: bevel;">pizazz</text> +</svg> diff --git a/tests/manual/svg/data/text/1.svg b/tests/manual/svg/data/text/1.svg new file mode 100644 index 0000000000..d6fd4905f0 --- /dev/null +++ b/tests/manual/svg/data/text/1.svg @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + width="210mm" + height="297mm" + viewBox="0 0 210 297" + version="1.1" + id="svg1" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <defs + id="defs1"> + <linearGradient + id="linearGradient1"> + <stop + style="stop-color:#ff0000;stop-opacity:1;" + offset="0" + id="stop1" /> + <stop + style="stop-color:#00ff00;stop-opacity:1;" + offset="1" + id="stop2" /> + </linearGradient> + <rect + x="150.02508" + y="181.45326" + width="412.12424" + height="148.24613" + id="rect1" /> + <linearGradient + xlink:href="#linearGradient1" + id="linearGradient2" + x1="159.13997" + y1="232.67492" + x2="543.63868" + y2="232.67492" + gradientUnits="userSpaceOnUse" /> + </defs> + <g id="layer1"> + <text xml:space="preserve" transform="scale(0.26458333)" id="text1" x="150.02539" y="266.60392" style="font-size:93.3333px;fill:url(#linearGradient2)"><tspan id="tspan3">FOO</tspan><tspan style="font-weight:bold;font-family:Dubai;-inkscape-font-specification:'Dubai Bold'">BAR</tspan></text> + </g> +</svg> diff --git a/tests/manual/svg/data/text/2.svg b/tests/manual/svg/data/text/2.svg new file mode 100644 index 0000000000..bf438e7aa0 --- /dev/null +++ b/tests/manual/svg/data/text/2.svg @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + width="210mm" + height="297mm" + viewBox="0 0 210 297" + version="1.1" + id="svg1" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <defs + id="defs1"> + <linearGradient + id="linearGradient1"> + <stop + style="stop-color:#ff0000;stop-opacity:1;" + offset="0" + id="stop1" /> + <stop + style="stop-color:#00ff00;stop-opacity:1;" + offset="1" + id="stop2" /> + </linearGradient> + <rect + x="150.02508" + y="181.45326" + width="412.12424" + height="148.24613" + id="rect1" /> + <linearGradient + xlink:href="#linearGradient1" + id="linearGradient2" + x1="159.13997" + y1="232.67492" + x2="543.63868" + y2="232.67492" + gradientUnits="userSpaceOnUse" /> + </defs> + <g id="layer1"> + <text xml:space="preserve" transform="scale(0.26458333)" id="text1" x="150.02539" y="266.60392" style="font-size:93.3333px;font-family:Cali;white-space:pre;shape-inside:url(#rect1);display:inline;opacity:0.557377;fill:url(#linearGradient2);stroke-width:1.00157"> + <tspan>FOO</tspan><tspan style="font-weight:bold;font-family:Dubai;-inkscape-font-specification:'Dubai Bold'">BAR</tspan></text> + </g> +</svg> diff --git a/tests/manual/svg/data/text/3.svg b/tests/manual/svg/data/text/3.svg new file mode 100644 index 0000000000..322cfff821 --- /dev/null +++ b/tests/manual/svg/data/text/3.svg @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + width="210mm" + height="297mm" + viewBox="0 0 210 297" + version="1.1" + id="svg1" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <defs + id="defs1"> + </defs> + <g id="layer1"> + <text xml:space="preserve" transform="scale(0.26458333)" id="text1" x="0" y="100" style="font-size:93.3333px;white-space:pre;shape-inside:url(#rect1);display:inline;opacity:0.557377;fill:#ff0000ff;stroke-width:1.00157"> + <tspan>FOO</tspan><tspan style="font-weight:bold;font-family:Dubai">BAR</tspan></text> + </g> +</svg> diff --git a/tests/manual/svg/data/text/4.svg b/tests/manual/svg/data/text/4.svg new file mode 100644 index 0000000000..d7146dedab --- /dev/null +++ b/tests/manual/svg/data/text/4.svg @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + width="210mm" + height="297mm" + viewBox="0 0 210 297" + version="1.1" + id="svg1" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <defs + id="defs1"> + </defs> + <g id="layer1"> + <text xml:space="preserve" transform="scale(0.26458333)" id="text1" x="0" y="100" style="font-size:93.3333px"> + <tspan style="fill: red">FO</tspan><tspan style="stroke: red">O</tspan><tspan style="font-weight:bold;font-family:Dubai">BAR</tspan></text> + </g> +</svg> diff --git a/tests/manual/svg/data/text/5.svg b/tests/manual/svg/data/text/5.svg new file mode 100644 index 0000000000..a63d53e526 --- /dev/null +++ b/tests/manual/svg/data/text/5.svg @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + width="210mm" + height="297mm" + viewBox="0 0 210 297" + version="1.1" + id="svg1" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <defs + id="defs1"> + <linearGradient + id="linearGradient1"> + <stop + style="stop-color:#ff0000;stop-opacity:1;" + offset="0" + id="stop1" /> + <stop + style="stop-color:#00ff00;stop-opacity:1;" + offset="1" + id="stop2" /> + </linearGradient> + <rect + x="150.02508" + y="181.45326" + width="412.12424" + height="148.24613" + id="rect1" /> + <linearGradient + xlink:href="#linearGradient1" + id="linearGradient2" + x1="159.13997" + y1="232.67492" + x2="543.63868" + y2="232.67492" + gradientUnits="userSpaceOnUse" /> + </defs> + <g id="layer1"> + <text xml:space="preserve" transform="scale(0.26458333)" id="text1" x="150.02539" y="266.60392" style="font-size:93.3333px"><tspan id="tspan3" style="stroke:red">FOO</tspan><tspan style="fill:url(#linearGradient2);font-weight:bold;font-family:Dubai;">BAR</tspan></text> + </g> +</svg> diff --git a/tests/manual/svg/main.cpp b/tests/manual/svg/main.cpp new file mode 100644 index 0000000000..d86d7a3793 --- /dev/null +++ b/tests/manual/svg/main.cpp @@ -0,0 +1,14 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "mainwindow.h" + +#include <QApplication> + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + return a.exec(); +} diff --git a/tests/manual/svg/mainwindow.cpp b/tests/manual/svg/mainwindow.cpp new file mode 100644 index 0000000000..403202514b --- /dev/null +++ b/tests/manual/svg/mainwindow.cpp @@ -0,0 +1,142 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "mainwindow.h" +#include "./ui_mainwindow.h" + +#include "svgmanager.h" +#include "svgpainter.h" + +#include <QFileDialog> +#include <QSettings> +#include <QQuickWidget> +#include <QQmlEngine> +#include <QSlider> + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::MainWindow) +{ + ui->setupUi(this); + + connect(ui->tbSelectDir, &QToolButton::clicked, this, &MainWindow::selectDirectory); + connect(ui->tbNext, &QToolButton::clicked, this, &MainWindow::next); + connect(ui->tbPrev, &QToolButton::clicked, this, &MainWindow::previous); + m_manager = new SvgManager(this); + + m_imageLabel = new QLabel; + m_imageLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop); + ui->saImage->setWidget(m_imageLabel); + ui->saImage->setBackgroundRole(QPalette::Base); + + m_svgPainter = new SvgPainter; + ui->saSvgPainter->setWidget(m_svgPainter); + ui->saSvgPainter->setBackgroundRole(QPalette::Base); + + m_svgImageWidget = new QQuickWidget; + m_svgImageWidget->setSource(QUrl(QStringLiteral("qrc:/SvgImageTest/SvgImage.qml"))); + m_svgImageWidget->setResizeMode(QQuickWidget::SizeViewToRootObject); + m_svgImageWidget->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); + ui->saSvgImage->setWidget(m_svgImageWidget); + + m_qmlGeneratorWidget = new QQuickWidget; + m_qmlGeneratorWidget->setSource(QUrl(QStringLiteral("qrc:/SvgImageTest/QmlGenerator.qml"))); + m_qmlGeneratorWidget->setResizeMode(QQuickWidget::SizeViewToRootObject); + m_qmlGeneratorWidget->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); + ui->saQmlGenerator->setWidget(m_qmlGeneratorWidget); + + connect(m_manager, &SvgManager::currentSourceChanged, this, &MainWindow::updateSources); + + m_settings = new QSettings(QStringLiteral("org.qtproject"), QStringLiteral("svg-test"), this); + + connect(ui->cbCurrentDir, &QComboBox::currentTextChanged, this, &MainWindow::loadDirectory); + QStringList list = m_settings->value(QStringLiteral("directories")).toString().split(QLatin1Char(',')); + setDirList(list); + + connect(ui->hsScale, &QAbstractSlider::valueChanged, m_manager, &SvgManager::setScale); + connect(ui->hsScale, &QAbstractSlider::valueChanged, m_svgPainter, &SvgPainter::setScale); + connect(ui->hsScale, &QAbstractSlider::valueChanged, this, &MainWindow::setScale); + int scale = m_settings->value(QStringLiteral("scale"), 10).toInt(); + ui->hsScale->setValue(scale); +} + +void MainWindow::loadDirectory(const QString &newDir) +{ + m_manager->setCurrentDirectory(newDir); +} + +void MainWindow::setDirList(const QStringList &list) +{ + ui->cbCurrentDir->clear(); + for (QString dirName : list) + ui->cbCurrentDir->addItem(dirName); + + m_settings->setValue(QStringLiteral("directories"), list.join(QLatin1Char(','))); +} + +void MainWindow::setScale(const int scale) +{ + m_settings->setValue(QStringLiteral("scale"), scale); +} + +void MainWindow::updateCurrentDir(const QString &s) +{ + QStringList list; + for (int i = 0; i < ui->cbCurrentDir->count(); ++i) { + if (ui->cbCurrentDir->itemText(i) != s) + list.append(ui->cbCurrentDir->itemText(i)); + } + + list.prepend(s); + + while (list.size() > 10) + list.removeLast(); + + setDirList(list); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +void MainWindow::updateSources() +{ + m_svgPainter->setSource(m_manager->currentSource()); + + QFileInfo info(m_manager->currentSource().toLocalFile()); + ui->lCurrentFileName->setText(info.baseName()); + + QFileInfo pngInfo(info.absolutePath() + QLatin1Char('/') + info.baseName() + QStringLiteral(".png")); + if (pngInfo.exists()) { + ui->lRefPng->setVisible(true); + ui->saImage->setVisible(true); + QPixmap pixmap = QPixmap::fromImage(QImage(pngInfo.absoluteFilePath())); + m_imageLabel->setPixmap(pixmap); + } else { + ui->lRefPng->setVisible(false); + ui->saImage->setVisible(false); + m_imageLabel->clear(); + } +} + +void MainWindow::selectDirectory() +{ + QString s = QFileDialog::getExistingDirectory(this, tr("Select directory"), m_manager->currentDirectory()); + if (!s.isEmpty()) { + updateCurrentDir(s); + } +} + +void MainWindow::next() +{ + if (m_manager->currentIndex() + 1 < m_manager->sourceCount()) + m_manager->setCurrentIndex(m_manager->currentIndex() + 1); +} + +void MainWindow::previous() +{ + if (m_manager->currentIndex() > 0) + m_manager->setCurrentIndex(m_manager->currentIndex() - 1); + +} diff --git a/tests/manual/svg/mainwindow.h b/tests/manual/svg/mainwindow.h new file mode 100644 index 0000000000..81e4bea113 --- /dev/null +++ b/tests/manual/svg/mainwindow.h @@ -0,0 +1,47 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include <QMainWindow> + +QT_BEGIN_NAMESPACE +namespace Ui { class MainWindow; } +QT_END_NAMESPACE + +class SvgPainter; +class SvgManager; +class QSettings; +class QLabel; +class QQuickWidget; + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + +private slots: + void updateSources(); + void selectDirectory(); + void next(); + void previous(); + void loadDirectory(const QString &newDir); + +private: + void updateCurrentDir(const QString &newDir); + void setDirList(const QStringList &list); + void setScale(const int scale); + + Ui::MainWindow *ui; + SvgManager *m_manager = nullptr; + QSettings *m_settings = nullptr; + QLabel *m_imageLabel = nullptr; + SvgPainter *m_svgPainter = nullptr; + QQuickWidget *m_svgImageWidget = nullptr; + QQuickWidget *m_qmlGeneratorWidget = nullptr; +}; +#endif // MAINWINDOW_H diff --git a/tests/manual/svg/mainwindow.ui b/tests/manual/svg/mainwindow.ui new file mode 100644 index 0000000000..ee75f1f49b --- /dev/null +++ b/tests/manual/svg/mainwindow.ui @@ -0,0 +1,292 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>1107</width> + <height>1003</height> + </rect> + </property> + <property name="windowTitle"> + <string>MainWindow</string> + </property> + <widget class="QWidget" name="centralwidget"> + <layout class="QVBoxLayout" name="verticalLayout_6"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <layout class="QVBoxLayout" name="vaRefPng"> + <item> + <widget class="QLabel" name="lRefPng"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Reference PNG</string> + </property> + </widget> + </item> + <item> + <widget class="QScrollArea" name="saImage"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Reference png</string> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <property name="alignment"> + <set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>263</width> + <height>789</height> + </rect> + </property> + </widget> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <widget class="QLabel" name="label_2"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>QSvgRenderer</string> + </property> + </widget> + </item> + <item> + <widget class="QScrollArea" name="saSvgPainter"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Reference QPainter</string> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents_4"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>264</width> + <height>789</height> + </rect> + </property> + </widget> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <item> + <widget class="QLabel" name="label_3"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>VectorImage</string> + </property> + </widget> + </item> + <item> + <widget class="QScrollArea" name="saSvgImage"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>QML generator</string> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents_2"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>263</width> + <height>789</height> + </rect> + </property> + </widget> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_5"> + <item> + <widget class="QLabel" name="label_4"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Qml Generator</string> + </property> + </widget> + </item> + <item> + <widget class="QScrollArea" name="saQmlGenerator"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>VectorImage</string> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents_3"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>263</width> + <height>789</height> + </rect> + </property> + </widget> + </widget> + </item> + </layout> + </item> + </layout> + </item> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Directory</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QComboBox" name="cbCurrentDir"> + <property name="maxCount"> + <number>10</number> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="tbSelectDir"> + <property name="text"> + <string>...</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <widget class="QToolButton" name="tbPrev"> + <property name="text"> + <string>⬅️</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="lCurrentFileName"> + <property name="text"> + <string>Filename</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="tbNext"> + <property name="font"> + <font> + <family>Segoe UI Emoji</family> + </font> + </property> + <property name="text"> + <string>➡️</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QSlider" name="hsScale"> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>100</number> + </property> + <property name="value"> + <number>10</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QMenuBar" name="menubar"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>1107</width> + <height>22</height> + </rect> + </property> + </widget> + <widget class="QStatusBar" name="statusbar"/> + </widget> + <resources/> + <connections/> +</ui> diff --git a/tests/manual/svg/svgmanager.cpp b/tests/manual/svg/svgmanager.cpp new file mode 100644 index 0000000000..b8d49413a5 --- /dev/null +++ b/tests/manual/svg/svgmanager.cpp @@ -0,0 +1,96 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "svgmanager.h" + +#include <QDir> +#include <QtQuickVectorImageGenerator/private/qquickqmlgenerator_p.h> +#include <QTemporaryFile> + +SvgManager *SvgManager::g_manager = nullptr; + +SvgManager::SvgManager(QObject *parent) + : QObject(parent) +{ + Q_ASSERT(g_manager == nullptr); + g_manager = this; + connect(this, &SvgManager::currentIndexChanged, this, &SvgManager::currentSourceChanged, Qt::QueuedConnection); +} + +SvgManager::~SvgManager() +{ + Q_ASSERT(g_manager == this); + g_manager = nullptr; +} + +void SvgManager::setCurrentIndex(int newCurrentIndex) +{ + if (m_currentIndex == newCurrentIndex) + return; + m_currentIndex = newCurrentIndex; + emit currentIndexChanged(); +} + +QList<QUrl> SvgManager::sources() const +{ + return m_sources; +} + +QString SvgManager::currentDirectory() const +{ + return m_currentDirectory; +} + +void SvgManager::setCurrentDirectory(const QString &newCurrentDirectory) +{ + if (m_currentDirectory == newCurrentDirectory) + return; + m_currentDirectory = newCurrentDirectory; + emit currentDirectoryChanged(); + + m_sources.clear(); + if (!m_currentDirectory.isEmpty()) { + QDir dir(m_currentDirectory); + QList<QFileInfo> infos = dir.entryInfoList(QStringList() << QStringLiteral("*.svg")); + + for (const QFileInfo &info : infos) + m_sources.append(QUrl::fromLocalFile(info.absoluteFilePath())); + } + m_currentIndex = m_sources.isEmpty() ? -1 : 0; + emit sourcesChanged(); + emit currentIndexChanged(); +} + +QString SvgManager::qmlSource() const +{ + QTemporaryFile tempFile; + if (tempFile.open()) { + QString name = tempFile.fileName(); + { + QQuickQmlGenerator generator(currentSource().toLocalFile(), QQuickVectorImageGenerator::CurveRenderer, tempFile.fileName()); + generator.setCommentString(QStringLiteral("Generated")); + generator.generate(); + } + tempFile.close(); + + QFile file(name); + if (file.open(QIODevice::ReadOnly)) + return QString::fromUtf8(file.readAll()); + + } + + return QStringLiteral("import QtQuick\nRectangle { width: 100; height: 100; color: \"red\" }");; +} + +qreal SvgManager::scale() const +{ + return m_scale; +} + +void SvgManager::setScale(int newScale) +{ + if (qFuzzyCompare(m_scale, newScale)) + return; + m_scale = newScale; + emit scaleChanged(); +} diff --git a/tests/manual/svg/svgmanager.h b/tests/manual/svg/svgmanager.h new file mode 100644 index 0000000000..bdfb20242d --- /dev/null +++ b/tests/manual/svg/svgmanager.h @@ -0,0 +1,82 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#ifndef SVGMANAGER_H +#define SVGMANAGER_H + +#include <QObject> +#include <QUrl> +#include <QQmlEngine> + +class SvgManager : public QObject +{ + Q_OBJECT + QML_ELEMENT + QML_SINGLETON + Q_PROPERTY(QUrl currentSource READ currentSource NOTIFY currentSourceChanged) + Q_PROPERTY(QString qmlSource READ qmlSource NOTIFY currentSourceChanged) + Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged) + Q_PROPERTY(int sourceCount READ sourceCount NOTIFY sourcesChanged) + Q_PROPERTY(QString currentDirectory READ currentDirectory WRITE setCurrentDirectory NOTIFY currentDirectoryChanged) + Q_PROPERTY(QList<QUrl> sources READ sources NOTIFY sourcesChanged) + Q_PROPERTY(qreal scale READ scale WRITE setScale NOTIFY scaleChanged) +public: + SvgManager(QObject *parent); + ~SvgManager() override; + + static SvgManager *create(QQmlEngine *, QJSEngine *) + { + return g_manager; + } + + QUrl currentSource() const + { + if (m_currentIndex < 0) + return QUrl{}; + + return m_sources.at(m_currentIndex); + } + + int currentIndex() const + { + return m_currentIndex; + } + void setCurrentIndex(int newCurrentIndex); + + int sourceCount() const + { + return m_sources.size(); + } + + QList<QUrl> sources() const; + + QString currentDirectory() const; + void setCurrentDirectory(const QString &newCurrentDirectory); + + QString qmlSource() const; + + qreal scale() const; + +public slots: + void setScale(int newScale); + +signals: + void currentSourceChanged(); + void currentIndexChanged(); + + void sourcesChanged(); + + void currentDirectoryChanged(); + + void scaleChanged(); + +private: + static SvgManager *g_manager; + int m_currentIndex = -1; + QList<QUrl> m_sources; + QString m_currentDirectory; + QString m_qmlSource; + qreal m_scale = 10.0; +}; + +#endif // SVGMANAGER_H diff --git a/tests/manual/svg/svgpainter.cpp b/tests/manual/svg/svgpainter.cpp new file mode 100644 index 0000000000..e040c1d087 --- /dev/null +++ b/tests/manual/svg/svgpainter.cpp @@ -0,0 +1,81 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "svgpainter.h" +#include "svgmanager.h" + +#include <QtSvg> + +SvgPainter::SvgPainter(QWidget *parent) +#ifdef SVGWIDGET + : QSvgWidget{parent} +#else + : QWidget{parent} +#endif + , m_scale(10) +{ +#ifndef SVGWIDGET + connect(this, SIGNAL(sourceChanged()), this, SLOT(update())); +#endif + + connect(this, SIGNAL(scaleChanged()), this, SLOT(update())); +} + +QUrl SvgPainter::source() const +{ + return m_source; +} + +void SvgPainter::setSource(const QUrl &newSource) +{ + if (m_source == newSource) + return; + m_source = newSource; +#ifdef SVGWIDGET + load(m_source.toLocalFile()); +#endif + emit sourceChanged(); +} + +qreal SvgPainter::scale() const +{ + return m_scale; +} + +void SvgPainter::setScale(const qreal scale) +{ + if (m_scale == scale) + return; + m_scale = scale; + emit scaleChanged(); +} + +#ifndef SVGWIDGET +QSize SvgPainter::sizeHint() const +{ + return !m_source.isEmpty() ? m_size * m_scale / 10.0 : QSize(1, 1); +} +#endif + +void SvgPainter::paintEvent(QPaintEvent *event) +{ +#ifndef SVGWIDGET + Q_UNUSED(event) + if (!m_source.isEmpty()) { + QPainter p(this); + p.fillRect(rect(), Qt::white); + QSvgRenderer renderer(m_source.toLocalFile()); + + renderer.setAspectRatioMode(Qt::KeepAspectRatio); + renderer.render(&p); + m_size = renderer.defaultSize(); + setFixedSize(m_size * m_scale / 10.0); + } +#else + m_size = renderer()->defaultSize(); + setFixedSize(m_size * m_scale / 10.0); + QSvgWidget::paintEvent(event); +#endif + +} + diff --git a/tests/manual/svg/svgpainter.h b/tests/manual/svg/svgpainter.h new file mode 100644 index 0000000000..5e8a641bd7 --- /dev/null +++ b/tests/manual/svg/svgpainter.h @@ -0,0 +1,49 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#ifndef SVGPAINTER_H +#define SVGPAINTER_H + +#include <QWidget> +#include <QUrl> +#include <QtSvgWidgets/QSvgWidget> + +// #define SVGWIDGET + +#ifdef SVGWIDGET +class SvgPainter : public QSvgWidget +#else +class SvgPainter : public QWidget +#endif +{ + Q_OBJECT + Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(qreal scale READ scale WRITE setScale NOTIFY scaleChanged) +public: + explicit SvgPainter(QWidget *parent = nullptr); + + QUrl source() const; + void setSource(const QUrl &newSource); + + qreal scale() const; + void setScale(const qreal scale); + +signals: + void sourceChanged(); + void scaleChanged(); + + +protected: +#ifndef SVGWIDGET + QSize sizeHint() const override; +#endif + void paintEvent(QPaintEvent *) override; + + +private: + QUrl m_source; + QSize m_size; + qreal m_scale; +}; + +#endif // SVGPAINTER_H |