| 1 | // Copyright (C) 2020 The Qt Company Ltd. |
| 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
| 3 | |
| 4 | #include "qsvgwidget.h" |
| 5 | |
| 6 | #include <qsvgrenderer.h> |
| 7 | |
| 8 | #include "qstyleoption.h" |
| 9 | #include "qpainter.h" |
| 10 | #include <QtWidgets/private/qwidget_p.h> |
| 11 | |
| 12 | QT_BEGIN_NAMESPACE |
| 13 | |
| 14 | /*! |
| 15 | \class QSvgWidget |
| 16 | \inmodule QtSvgWidgets |
| 17 | \ingroup painting |
| 18 | |
| 19 | \brief The QSvgWidget class provides a widget that is used to display the contents of |
| 20 | Scalable Vector Graphics (SVG) files. |
| 21 | \since 4.1 |
| 22 | |
| 23 | This class enables developers to display SVG drawings alongside standard widgets, and |
| 24 | is used in much the same way as QLabel is used for displaying text and bitmap images. |
| 25 | |
| 26 | Since QSvgWidget is a subclass of QWidget, SVG drawings are rendered using the properties |
| 27 | of the display. More control can be exercised over the rendering process with the |
| 28 | QSvgRenderer class, as this can be used to paint onto other paint devices, such as QImage |
| 29 | and QGLWidget. The renderer used by the widget can be obtained with the renderer() |
| 30 | function. |
| 31 | |
| 32 | Each QSvgWidget can be constructed with the file name of a SVG file, or they can be |
| 33 | constructed without a specific file to render and one can be supplied later. The load() |
| 34 | functions provide two different ways to load an SVG file: they accept either the file name |
| 35 | of an SVG file or a QByteArray containing the serialized XML representation of an SVG file. |
| 36 | |
| 37 | By default, the widget provides a size hint to reflect the size of the drawing that it |
| 38 | displays. If no data has been loaded, the widget provides the default QWidget size hint. |
| 39 | Subclass this class and reimplement sizeHint() if you need to customize this behavior. |
| 40 | |
| 41 | \sa QSvgRenderer, {Qt SVG C++ Classes}, QPicture |
| 42 | */ |
| 43 | |
| 44 | class QSvgWidgetPrivate : public QWidgetPrivate |
| 45 | { |
| 46 | Q_DECLARE_PUBLIC(QSvgWidget) |
| 47 | public: |
| 48 | QSvgRenderer *renderer; |
| 49 | }; |
| 50 | |
| 51 | // Event listener for ShowEvent/HideEvent on QSvgWidget (which can't just |
| 52 | // reimplement event() or showEvent()/hideEvent() or eventFilter() in case |
| 53 | // a subclass doesn't call the base class in those methods) |
| 54 | // ### Qt 7: remove the event filter; move this logic into showEvent/hideEvent; add event() override |
| 55 | class QSvgWidgetListener : public QObject |
| 56 | { |
| 57 | public: |
| 58 | using QObject::QObject; |
| 59 | |
| 60 | protected: |
| 61 | bool eventFilter(QObject *obj, QEvent *event) override |
| 62 | { |
| 63 | if (event->type() == QEvent::Show) |
| 64 | renderer()->setAnimationEnabled(true); |
| 65 | else if (event->type() == QEvent::Hide) |
| 66 | renderer()->setAnimationEnabled(false); |
| 67 | return QObject::eventFilter(watched: obj, event); |
| 68 | } |
| 69 | |
| 70 | private: |
| 71 | QSvgRenderer *renderer() |
| 72 | { |
| 73 | return static_cast<QSvgWidgetPrivate *>(QObjectPrivate::get(o: parent()))->renderer; |
| 74 | } |
| 75 | }; |
| 76 | |
| 77 | /*! |
| 78 | Constructs a new SVG display widget with the given \a parent. |
| 79 | */ |
| 80 | QSvgWidget::QSvgWidget(QWidget *parent) |
| 81 | : QWidget(*new QSvgWidgetPrivate, parent, {}) |
| 82 | { |
| 83 | d_func()->renderer = new QSvgRenderer(this); |
| 84 | QObject::connect(sender: d_func()->renderer, SIGNAL(repaintNeeded()), |
| 85 | receiver: this, SLOT(update())); |
| 86 | installEventFilter(filterObj: new QSvgWidgetListener(this)); |
| 87 | } |
| 88 | |
| 89 | /*! |
| 90 | Constructs a new SVG display widget with the given \a parent and loads the contents |
| 91 | of the specified \a file. |
| 92 | */ |
| 93 | QSvgWidget::QSvgWidget(const QString &file, QWidget *parent) |
| 94 | : QSvgWidget(parent) |
| 95 | { |
| 96 | d_func()->renderer->load(filename: file); |
| 97 | } |
| 98 | |
| 99 | /*! |
| 100 | Destroys the widget. |
| 101 | */ |
| 102 | QSvgWidget::~QSvgWidget() |
| 103 | { |
| 104 | |
| 105 | } |
| 106 | |
| 107 | /*! |
| 108 | Returns the renderer used to display the contents of the widget. |
| 109 | */ |
| 110 | QSvgRenderer * QSvgWidget::renderer() const |
| 111 | { |
| 112 | Q_D(const QSvgWidget); |
| 113 | return d->renderer; |
| 114 | } |
| 115 | |
| 116 | |
| 117 | /*! |
| 118 | \reimp |
| 119 | */ |
| 120 | QSize QSvgWidget::sizeHint() const |
| 121 | { |
| 122 | Q_D(const QSvgWidget); |
| 123 | if (d->renderer->isValid()) |
| 124 | return d->renderer->defaultSize(); |
| 125 | else |
| 126 | return QSize(128, 64); |
| 127 | } |
| 128 | |
| 129 | /*! |
| 130 | \since 6.7 |
| 131 | |
| 132 | Returns the options of the widget's renderer. |
| 133 | |
| 134 | \sa setOptions |
| 135 | */ |
| 136 | QtSvg::Options QSvgWidget::options() const |
| 137 | { |
| 138 | Q_D(const QSvgWidget); |
| 139 | return d->renderer->options(); |
| 140 | } |
| 141 | |
| 142 | /*! |
| 143 | \since 6.7 |
| 144 | |
| 145 | Sets the widget's renderer options to \a options. |
| 146 | |
| 147 | This property holds a set of QtSvg::Option flags that can be used |
| 148 | to enable or disable various features of the parsing and rendering |
| 149 | of SVG files. It must be set before calling the load function to |
| 150 | have any effect. |
| 151 | |
| 152 | By default, no flags are set. |
| 153 | |
| 154 | \sa options |
| 155 | */ |
| 156 | void QSvgWidget::setOptions(QtSvg::Options options) |
| 157 | { |
| 158 | Q_D(QSvgWidget); |
| 159 | d->renderer->setOptions(options); |
| 160 | } |
| 161 | |
| 162 | /*! |
| 163 | \reimp |
| 164 | */ |
| 165 | void QSvgWidget::paintEvent(QPaintEvent *) |
| 166 | { |
| 167 | Q_D(QSvgWidget); |
| 168 | QStyleOption opt; |
| 169 | opt.initFrom(w: this); |
| 170 | QPainter p(this); |
| 171 | style()->drawPrimitive(pe: QStyle::PE_Widget, opt: &opt, p: &p, w: this); |
| 172 | d->renderer->render(p: &p); |
| 173 | } |
| 174 | |
| 175 | /*! |
| 176 | Loads the contents of the specified SVG \a file and updates the widget. |
| 177 | */ |
| 178 | void QSvgWidget::load(const QString &file) |
| 179 | { |
| 180 | Q_D(const QSvgWidget); |
| 181 | d->renderer->load(filename: file); |
| 182 | if (!isVisible()) |
| 183 | d->renderer->setAnimationEnabled(false); |
| 184 | } |
| 185 | |
| 186 | /*! |
| 187 | Loads the specified SVG format \a contents and updates the widget. |
| 188 | */ |
| 189 | void QSvgWidget::load(const QByteArray &contents) |
| 190 | { |
| 191 | Q_D(const QSvgWidget); |
| 192 | d->renderer->load(contents); |
| 193 | if (!isVisible()) |
| 194 | d->renderer->setAnimationEnabled(false); |
| 195 | } |
| 196 | |
| 197 | QT_END_NAMESPACE |
| 198 | |