version 2.18.0

add GraphicRanges to graphic library
new graphic_analysis library
This commit is contained in:
2023-07-31 20:17:34 +03:00
parent 2a063a4f00
commit d98e8c1f30
24 changed files with 1524 additions and 383 deletions

View File

@@ -0,0 +1,6 @@
find_package(PIP)
if (PIP_FOUND)
qad_library(graphic_analysis "Gui;Positioning" "PIP::FFTW;qad_graphic")
endif()

View File

@@ -0,0 +1,321 @@
#include "graphic_analysis.h"
#include "qad_types.h"
#include "ui_graphic_analysis.h"
#include <QTimer>
#include <pifft.h>
PIVector<double> getAmplitude(const PIVector<complexd> & result) {
PIVector<double> ret;
ret.resize(result.size());
double tmp;
for (uint i = 0; i < result.size(); i++) {
tmp = sqrt(result[i].real() * result[i].real() + result[i].imag() * result[i].imag());
ret[i] = tmp;
}
return ret;
}
PIVector<double> spectrumPIVector(PIFFTWd & fft, const PIVector<double> & in, double frequency, QPointF * fft_mul = nullptr) {
PIVector<double> ret;
if (in.size() <= 2 || frequency <= 0.) return ret;
ret = getAmplitude(fft.calcFFT(in));
ret.resize(ret.size_s() / 2);
ret[0] = 0.;
if (fft_mul) *fft_mul = QPointF(frequency / ret.size_s() / 2., 1. / ret.size_s());
return ret;
}
QPolygonF spectrumQPolygonF(PIFFTWd & fft, const PIVector<double> & in, double frequency, QPointF * fft_mul = nullptr) {
QPolygonF ret;
QPointF mul;
PIVector<double> spec = spectrumPIVector(fft, in, frequency, &mul);
if (spec.isEmpty()) return ret;
ret.resize(spec.size_s());
for (int i = 0; i < ret.size(); ++i)
ret[i] = QPointF(i * mul.x(), spec[i] * mul.y());
if (fft_mul) *fft_mul = mul;
return ret;
}
// GraphicAnalysis
PRIVATE_DEFINITION_START(GraphicAnalysis)
PIFFTWd fft;
PRIVATE_DEFINITION_END(GraphicAnalysis)
GraphicAnalysis::GraphicAnalysis(QWidget * parent): GraphicRanges(parent) {
widget_toolbox = new QWidget();
ui = new Ui::GraphicAnalysis();
ui->setupUi(widget_toolbox);
ui->widgetSpectrum->hide();
connect(ui->checkSpectrum, SIGNAL(toggled(bool)), this, SLOT(checkSpectrum_toggled(bool)));
connect(ui->buttonSpectrumRange, SIGNAL(toggled(bool)), this, SLOT(buttonSpectrumRange_toggled(bool)));
connect(ui->checkSpectrumFixDuration, SIGNAL(toggled(bool)), this, SLOT(checkSpectrumFixDuration_toggled(bool)));
auto * lay = qobject_cast<QBoxLayout *>(layout());
lay->insertWidget(0, widget_toolbox);
connect(ui->spinSpectrumDuration, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
connect(this, SIGNAL(rangeSelected(double, double)), this, SLOT(gaRangeSelected(double, double)));
connect(this, SIGNAL(graphicMousePressEvent(QPointF, int)), this, SLOT(gaMousePressEvent(QPointF, int)));
connect(this, SIGNAL(graphicMouseMoveEvent(QPointF, int)), this, SLOT(gaMouseMoveEvent(QPointF, int)));
connect(this, SIGNAL(graphicMouseReleaseEvent(QPointF, int)), this, SLOT(gaMouseReleaseEvent(QPointF, int)));
}
GraphicAnalysis::~GraphicAnalysis() {
delete ui;
delete widget_toolbox;
}
void GraphicAnalysis::setGraphicData(const QPolygonF & g, int graphic, bool update_) {
if (graphic < 0 || graphic >= graphicsCount()) return;
src_data[graphic] = g;
updateGraphic(graphic);
if (update_) viewport()->update();
}
bool GraphicAnalysis::isSpectrumFixedDuration() const {
return ui->checkSpectrumFixDuration->isChecked();
}
void GraphicAnalysis::setIsSpectrumFixedDuration(bool on) {
ui->checkSpectrumFixDuration->setChecked(on);
}
double GraphicAnalysis::spectrumFixedDuration() const {
return ui->spinSpectrumDuration->value();
}
void GraphicAnalysis::setSpectrumFixedDuration(double val) {
ui->spinSpectrumDuration->setValue(val);
}
bool GraphicAnalysis::isToolboxVisible() const {
return widget_toolbox->isVisible();
}
void GraphicAnalysis::setToolboxVisible(bool yes) {
widget_toolbox->setVisible(yes);
}
void GraphicAnalysis::setLabelX(const QString & str) {
data_label_x = str;
if (!show_fft) Graphic::setLabelX(str);
}
QBoxLayout * GraphicAnalysis::toolboxLayout() {
return reinterpret_cast<QBoxLayout *>(widget_toolbox->layout());
}
QWidget * GraphicAnalysis::toolboxWidget() {
return widget_toolbox;
}
bool GraphicAnalysis::isShowSpectrum() const {
return show_fft;
}
void GraphicAnalysis::changeEvent(QEvent * e) {
Graphic::changeEvent(e);
if (e->type() == QEvent::LanguageChange) {
ui->retranslateUi(this);
return;
}
}
void GraphicAnalysis::updateGraphic(int index) {
if (!show_fft) {
if (tf_gr)
Graphic::setGraphicData(tf_gr(src_data.value(index)), index, false);
else
Graphic::setGraphicData(src_data.value(index), index, false);
} else {
const QPolygonF & src(src_data[index]);
int si = 0, ei = src.size() - 1;
for (int i = 0; i < src.size(); ++i) {
if (src[i].x() >= range_fft.start) {
si = i;
break;
}
}
for (int i = si; i < src.size(); ++i) {
if (src[i].x() > range_fft.end) {
ei = i;
break;
}
}
if (ei - si < 4) {
Graphic::setGraphicData({}, index, false);
return;
}
if (tf_fft)
Graphic::setGraphicData(tf_fft(calcToFFT(&(src[si]), ei - si)), index, false);
else
Graphic::setGraphicData(calcToFFT(&(src[si]), ei - si), index, false);
}
}
void GraphicAnalysis::updateAllGraphic() {
for (int i = 0; i < graphicsCount(); ++i)
updateGraphic(i);
}
void GraphicAnalysis::setFFT(bool on) {
if (show_fft) {
setFFTInternal(false);
}
if (on) {
range_fft = rangeVisible();
setFFTInternal(true);
}
}
void GraphicAnalysis::setFFTInternal(bool on) {
bool need_autofit = false;
if (!show_fft && on) {
saved_view = visualRect();
saved_autofit = isAutofitted();
need_autofit = true;
}
if (show_fft && !on) {
setVisualRect(saved_view);
if (saved_autofit) need_autofit = true;
}
show_fft = on;
Graphic::setLabelX(on ? tr("Hz") : data_label_x);
emit showSpectrumChanged(show_fft);
updateAllGraphic();
if (need_autofit) {
autofit();
}
}
QPolygonF GraphicAnalysis::calcToFFT(const QPointF * in, int count) {
PIVector<double> fft_in, fft_out;
fft_in.reserve(count);
for (int i = 0; i < count; ++i)
fft_in << in[i].y();
double freq = double(count - 1) / (in[count - 1].x() - in[0].x());
return spectrumQPolygonF(PRIVATE->fft, fft_in, freq);
}
void GraphicAnalysis::checkRangeRequest() {
if (!ui->buttonSpectrumRange->isChecked()) return;
viewport()->unsetCursor();
if (!ui->checkSpectrumFixDuration->isChecked()) {
rangeRequest();
} else {
cancelRangeRequest(false);
viewport()->setCursor(Qt::CrossCursor);
}
}
void GraphicAnalysis::clear() {
src_data.clear();
Graphic::clear();
}
void GraphicAnalysis::setGraphicsCount(int cnt, bool update) {
for (int i = cnt; i < graphicsCount(); ++i)
src_data.remove(i);
Graphic::setGraphicsCount(cnt, update);
}
void GraphicAnalysis::addPoint(const QPointF & p, int graphic, bool update_) {
src_data[graphic] << p;
if (show_fft) return;
Graphic::addPoint(p, graphic, update_);
}
void GraphicAnalysis::setGraphicTransformFunction(std::function<QPolygonF(const QPolygonF &)> f) {
tf_gr = f;
}
void GraphicAnalysis::setSpectrumTransformFunction(std::function<QPolygonF(const QPolygonF &)> f) {
tf_fft = f;
}
void GraphicAnalysis::gaMousePressEvent(QPointF point, int buttons) {
if (!ui->buttonSpectrumRange->isChecked() || buttons != Qt::LeftButton || !ui->checkSpectrumFixDuration->isChecked()) return;
setNavigationEnabled(false);
graphicMouseMoveEvent(point, buttons);
}
void GraphicAnalysis::gaMouseMoveEvent(QPointF point, int buttons) {
if (!ui->buttonSpectrumRange->isChecked() || buttons != Qt::LeftButton || !ui->checkSpectrumFixDuration->isChecked()) return;
setCurrentRange(point.x(), point.x() + ui->spinSpectrumDuration->value());
}
void GraphicAnalysis::gaMouseReleaseEvent(QPointF point, int buttons) {
if (!ui->buttonSpectrumRange->isChecked() || buttons != Qt::LeftButton || !ui->checkSpectrumFixDuration->isChecked()) return;
auto r = currentRange();
clearCurrentRange();
gaRangeSelected(r.start, r.end);
viewport()->setCursor(Qt::ArrowCursor);
QTimer::singleShot(10, [this]() {
setNavigationEnabled(true);
update();
});
}
void GraphicAnalysis::gaRangeSelected(double start, double end) {
if (!ui->buttonSpectrumRange->isChecked()) return;
ui->buttonSpectrumRange->setChecked(false);
range_fft = GraphicRanges::Range(start, end);
updateAllGraphic();
}
void GraphicAnalysis::checkSpectrum_toggled(bool on) {
if (!on) ui->buttonSpectrumRange->setChecked(false);
setFFT(on);
}
void GraphicAnalysis::buttonSpectrumRange_toggled(bool on) {
setFFT(!on);
if (on)
checkRangeRequest();
else
viewport()->unsetCursor();
}
void GraphicAnalysis::checkSpectrumFixDuration_toggled(bool on) {
checkRangeRequest();
emit configChanged();
}

View File

@@ -0,0 +1,101 @@
/*
QAD - Qt ADvanced
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef graphic_analysis_h
#define graphic_analysis_h
#include "qad_graphic_analysis_export.h"
#include <graphic_ranges.h>
#include <pibase_macros.h>
namespace Ui {
class GraphicAnalysis;
}
class GraphicAnalysisPlugin;
class QAD_GRAPHIC_ANALYSIS_EXPORT GraphicAnalysis: public GraphicRanges {
Q_OBJECT
friend class GraphicAnalysisPlugin;
Q_PROPERTY(bool toolboxVisible READ isToolboxVisible WRITE setToolboxVisible)
public:
GraphicAnalysis(QWidget * parent = 0);
virtual ~GraphicAnalysis();
void setGraphicData(const QPolygonF & g, int graphic, bool update_ = true);
bool isSpectrumFixedDuration() const;
void setIsSpectrumFixedDuration(bool on);
double spectrumFixedDuration() const;
void setSpectrumFixedDuration(double val);
bool isToolboxVisible() const;
void setToolboxVisible(bool yes);
void setLabelX(const QString & str);
QBoxLayout * toolboxLayout();
QWidget * toolboxWidget();
bool isShowSpectrum() const;
void setGraphicsCount(int cnt, bool update = true);
void addPoint(const QPointF & p, int graphic, bool update_ = true);
void setGraphicTransformFunction(std::function<QPolygonF(const QPolygonF &)> f);
void setSpectrumTransformFunction(std::function<QPolygonF(const QPolygonF &)> f);
protected:
void changeEvent(QEvent * e);
void updateGraphic(int index);
void updateAllGraphic();
void setFFTInternal(bool on);
void setFFT(bool on);
QPolygonF calcToFFT(const QPointF * in, int count);
void checkRangeRequest();
Ui::GraphicAnalysis * ui = nullptr;
QWidget * widget_toolbox = nullptr;
QMap<int, QPolygonF> src_data;
GraphicRanges::Range range_fft;
std::function<QPolygonF(const QPolygonF &)> tf_gr, tf_fft;
QString data_label_x;
QRectF saved_view;
bool saved_autofit = true, show_fft = false;
PRIVATE_DECLARATION(QAD_GRAPHIC_ANALYSIS_EXPORT)
public slots:
void clear();
private slots:
void gaMousePressEvent(QPointF point, int buttons);
void gaMouseMoveEvent(QPointF point, int buttons);
void gaMouseReleaseEvent(QPointF point, int buttons);
void gaRangeSelected(double start, double end);
void checkSpectrum_toggled(bool on);
void buttonSpectrumRange_toggled(bool on);
void checkSpectrumFixDuration_toggled(bool on);
signals:
void showSpectrumChanged(bool);
void configChanged();
};
#endif

View File

@@ -0,0 +1,199 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>GraphicAnalysis</class>
<widget class="QWidget" name="GraphicAnalysis">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>488</width>
<height>57</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<item>
<widget class="QCheckBox" name="checkSpectrum">
<property name="text">
<string>Spectrum</string>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="widgetSpectrum" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QToolButton" name="buttonSpectrumRange">
<property name="toolTip">
<string>Select spectrum input data</string>
</property>
<property name="icon">
<iconset resource="qad_graphic_analysis.qrc">
<normaloff>:/icons/axis_x.png</normaloff>:/icons/axis_x.png</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Preferred</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QWidget" name="widgetFixedDuration" native="true">
<property name="enabled">
<bool>false</bool>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QCheckBox" name="checkSpectrumFixDuration">
<property name="text">
<string>Fix dur.:</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="spinSpectrumDuration">
<property name="enabled">
<bool>false</bool>
</property>
<property name="suffix">
<string> s</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>0.001000000000000</double>
</property>
<property name="maximum">
<double>99999.000000000000000</double>
</property>
<property name="singleStep">
<double>10.000000000000000</double>
</property>
<property name="value">
<double>100.000000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>104</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources>
<include location="qad_graphic_analysis.qrc"/>
</resources>
<connections>
<connection>
<sender>checkSpectrum</sender>
<signal>toggled(bool)</signal>
<receiver>widgetSpectrum</receiver>
<slot>setVisible(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>90</x>
<y>19</y>
</hint>
<hint type="destinationlabel">
<x>152</x>
<y>5</y>
</hint>
</hints>
</connection>
<connection>
<sender>checkSpectrumFixDuration</sender>
<signal>toggled(bool)</signal>
<receiver>spinSpectrumDuration</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>209</x>
<y>24</y>
</hint>
<hint type="destinationlabel">
<x>289</x>
<y>20</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonSpectrumRange</sender>
<signal>toggled(bool)</signal>
<receiver>widgetFixedDuration</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>126</x>
<y>30</y>
</hint>
<hint type="destinationlabel">
<x>181</x>
<y>45</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="en_US">
<context>
<name>GraphicAnalysis</name>
<message>
<location filename="../graphic_analysis.ui" line="26"/>
<source>Spectrum</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../graphic_analysis.ui" line="48"/>
<source>Select spectrum input data</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../graphic_analysis.ui" line="96"/>
<source>Fix dur.:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../graphic_analysis.ui" line="106"/>
<source> s</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../graphic_analysis.cpp" line="178"/>
<source>Hz</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="ru_RU">
<context>
<name>GraphicAnalysis</name>
<message>
<location filename="../graphic_analysis.ui" line="26"/>
<source>Spectrum</source>
<translation>Спектр</translation>
</message>
<message>
<location filename="../graphic_analysis.ui" line="48"/>
<source>Select spectrum input data</source>
<translation>Выбрать данные для построения спектра</translation>
</message>
<message>
<location filename="../graphic_analysis.ui" line="96"/>
<source>Fix dur.:</source>
<translation>Фикс. длит.:</translation>
</message>
<message>
<location filename="../graphic_analysis.ui" line="106"/>
<source> s</source>
<translation> с</translation>
</message>
<message>
<location filename="../graphic_analysis.cpp" line="178"/>
<source>Hz</source>
<translation>Гц</translation>
</message>
</context>
</TS>

View File

@@ -0,0 +1,2 @@
lupdate ../ -ts qad_graphic_analysis_ru.ts
lupdate ../ -ts qad_graphic_analysis_en.ts

View File

@@ -0,0 +1 @@
qad_plugin(graphic_analysis "Gui;Widgets" "")

View File

@@ -0,0 +1,71 @@
#include "graphic_analysis_plugin.h"
#include "graphic_analysis.h"
#include <QDesignerFormEditorInterface>
#include <QExtensionManager>
#include <QtPlugin>
GraphicAnalysisPlugin::GraphicAnalysisPlugin(QObject * parent): QObject(parent) {
m_initialized = m_designer = false;
}
void GraphicAnalysisPlugin::initialize(QDesignerFormEditorInterface * core) {
m_designer = true;
if (m_initialized) return;
m_initialized = true;
}
bool GraphicAnalysisPlugin::isInitialized() const {
return m_initialized;
}
QWidget * GraphicAnalysisPlugin::createWidget(QWidget * parent) {
auto ret = new GraphicAnalysis(parent);
if (m_designer) ret->m_fakeGL = true;
return ret;
}
QString GraphicAnalysisPlugin::name() const {
return QLatin1String("GraphicAnalysis");
}
QString GraphicAnalysisPlugin::group() const {
return QLatin1String("Display Widgets");
}
QIcon GraphicAnalysisPlugin::icon() const {
return QIcon(":/icons/graphic.png");
}
QString GraphicAnalysisPlugin::toolTip() const {
return QLatin1String(""); // QLatin1String("Widget for display any math graphics with grid and navigation");
}
QString GraphicAnalysisPlugin::whatsThis() const {
return QLatin1String("");
}
bool GraphicAnalysisPlugin::isContainer() const {
return false;
}
QString GraphicAnalysisPlugin::domXml() const {
return QLatin1String("<widget class=\"GraphicAnalysis\" name=\"graphicAnalysis\">\n</widget>\n");
}
QString GraphicAnalysisPlugin::includeFile() const {
return QLatin1String("graphic_analysis.h");
}

View File

@@ -0,0 +1,40 @@
#ifndef GRAPHIC_analysis_PLUGIN_H
#define GRAPHIC_analysis_PLUGIN_H
#include <QObject>
#if QT_VERSION >= 0x050000
# include <QtUiPlugin/QDesignerCustomWidgetInterface>
#else
# include <QDesignerCustomWidgetInterface>
#endif
class GraphicAnalysis;
class GraphicAnalysisPlugin
: public QObject
, public QDesignerCustomWidgetInterface {
Q_OBJECT
Q_INTERFACES(QDesignerCustomWidgetInterface)
public:
GraphicAnalysisPlugin(QObject * parent = 0);
bool isContainer() const;
bool isInitialized() const;
QIcon icon() const;
QString domXml() const;
QString group() const;
QString includeFile() const;
QString name() const;
QString toolTip() const;
QString whatsThis() const;
QWidget * createWidget(QWidget * parent);
void initialize(QDesignerFormEditorInterface * core);
private:
bool m_initialized, m_designer;
};
#endif

View File

@@ -0,0 +1,17 @@
#include "qad_graphic_analysis.h"
#include "graphic_analysis_plugin.h"
QADGraphicAnalysis::QADGraphicAnalysis(QObject * parent): QObject(parent) {
m_widgets << new GraphicAnalysisPlugin(this);
}
QList<QDesignerCustomWidgetInterface *> QADGraphicAnalysis::customWidgets() const {
return m_widgets;
}
#if QT_VERSION < 0x050000
Q_EXPORT_PLUGIN2(qad_graphic_analysis_plugin, QADGraphicAnalysis)
#endif

View File

@@ -0,0 +1,24 @@
#ifndef QAD_GRAPHIC_H
#define QAD_GRAPHIC_H
#include <QtCore/qplugin.h>
#include <QtDesigner/QtDesigner>
class QADGraphicAnalysis
: public QObject
, public QDesignerCustomWidgetCollectionInterface {
Q_OBJECT
Q_INTERFACES(QDesignerCustomWidgetCollectionInterface)
#if QT_VERSION >= 0x050000
Q_PLUGIN_METADATA(IID "qad.graphic_analysis")
#endif
public:
explicit QADGraphicAnalysis(QObject * parent = 0);
virtual QList<QDesignerCustomWidgetInterface *> customWidgets() const;
private:
QList<QDesignerCustomWidgetInterface *> m_widgets;
};
#endif // QAD_GRAPHIC_H

View File

@@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/">
<file>../../icons/axis_x.png</file>
<file>../../icons/graphic.png</file>
</qresource>
</RCC>