New feature Background image. Closes #43

This commit is contained in:
Roman Telezhynskyi 2022-01-28 16:54:20 +02:00
parent 141b33884d
commit 357fd3a0ac
133 changed files with 8878 additions and 227 deletions

View file

@ -27,6 +27,7 @@
- Backport fix vulnerability CVE-2021-21900.
- Improved main path validations.
- New path validation Invalid segment.
- [smart-pattern/valentina#43] Background image.
# Valentina 0.7.49 July 1, 2021
- Fix crash.

View file

@ -657,7 +657,7 @@ void VPMainGraphicsView::SwitchScene(const VPSheetPtr &sheet)
{
VMainGraphicsScene *scene = sheet->SceneData()->Scene();
setScene(scene);
connect(scene, &VMainGraphicsScene::ItemClicked, this, &VPMainGraphicsView::on_ItemClicked,
connect(scene, &VMainGraphicsScene::ItemByMousePress, this, &VPMainGraphicsView::on_ItemClicked,
Qt::UniqueConnection);
connect(scene, &VMainGraphicsScene::mouseMove, this, &VPMainGraphicsView::on_SceneMouseMove,
Qt::UniqueConnection);

View file

@ -28,6 +28,8 @@
#include "vtooloptionspropertybrowser.h"
#include "../vtools/tools/drawTools/drawtools.h"
#include "../vtools/tools/backgroundimage/vbackgroundpixmapitem.h"
#include "../vtools/tools/backgroundimage/vbackgroundsvgitem.h"
#include "../core/vapplication.h"
#include "../vwidgets/vmaingraphicsview.h"
#include "../vwidgets/vgraphicssimpletextitem.h"
@ -46,6 +48,12 @@
#include <QDebug>
#include <QRegularExpression>
namespace
{
Q_GLOBAL_STATIC_WITH_ARGS(const QString, AttrHold, (QLatin1String("hold")))
Q_GLOBAL_STATIC_WITH_ARGS(const QString, AttrVisible, (QLatin1String("visible")))
}
//---------------------------------------------------------------------------------------------------------------------
VToolOptionsPropertyBrowser::VToolOptionsPropertyBrowser(QDockWidget *parent)
:QObject(parent), PropertyModel(nullptr), formView(nullptr), currentItem(nullptr),
@ -79,7 +87,7 @@ void VToolOptionsPropertyBrowser::ClearPropertyBrowser()
void VToolOptionsPropertyBrowser::ShowItemOptions(QGraphicsItem *item)
{
// This check helps to find missed tools in the switch
Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55, "Not all tools were used in switch.");
Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 59, "Not all tools were used in switch.");
switch (item->type())
{
@ -192,6 +200,12 @@ void VToolOptionsPropertyBrowser::ShowItemOptions(QGraphicsItem *item)
case VToolEllipticalArc::Type:
ShowOptionsToolEllipticalArc(item);
break;
case VBackgroundPixmapItem::Type:
ShowOptionsBackgroundPixmapItem(item);
break;
case VBackgroundSVGItem::Type:
ShowOptionsBackgroundSVGItem(item);
break;
default:
break;
}
@ -206,7 +220,7 @@ void VToolOptionsPropertyBrowser::UpdateOptions()
}
// This check helps to find missed tools in the switch
Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55, "Not all tools were used in switch.");
Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 59, "Not all tools were used in switch.");
switch (currentItem->type())
{
@ -316,6 +330,12 @@ void VToolOptionsPropertyBrowser::UpdateOptions()
case VToolEllipticalArc::Type:
UpdateOptionsToolEllipticalArc();
break;
case VBackgroundPixmapItem::Type:
UpdateOptionsBackgroundPixmapItem();
break;
case VBackgroundSVGItem::Type:
UpdateOptionsBackgroundSVGItem();
break;
default:
break;
}
@ -351,7 +371,7 @@ void VToolOptionsPropertyBrowser::userChangedData(VPE::VProperty *property)
}
// This check helps to find missed tools in the switch
Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55, "Not all tools were used in switch.");
Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 59, "Not all tools were used in switch.");
switch (currentItem->type())
{
@ -457,6 +477,12 @@ void VToolOptionsPropertyBrowser::userChangedData(VPE::VProperty *property)
case VToolEllipticalArc::Type:
ChangeDataToolEllipticalArc(prop);
break;
case VBackgroundPixmapItem::Type:
ChangeDataBackgroundPixmapItem(prop);
break;
case VBackgroundSVGItem::Type:
ChangeDataBackgroundSVGItem(prop);
break;
default:
break;
}
@ -613,6 +639,14 @@ void VToolOptionsPropertyBrowser::AddPropertyText(const QString &propertyName, c
AddProperty(itemText, attrName);
}
//---------------------------------------------------------------------------------------------------------------------
void VToolOptionsPropertyBrowser::AddPropertyBool(const QString &propertyName, bool value, const QString &attrName)
{
auto *itemBool = new VPE::VBoolProperty(propertyName);
itemBool->setValue(value);
AddProperty(itemBool, attrName);
}
//---------------------------------------------------------------------------------------------------------------------
template<class Tool>
void VToolOptionsPropertyBrowser::AddPropertyCrossPoint(Tool *i, const QString &propertyName)
@ -719,6 +753,66 @@ void VToolOptionsPropertyBrowser::AddPropertyApproximationScale(const QString &p
AddProperty(aScaleProperty, AttrAScale);
}
//---------------------------------------------------------------------------------------------------------------------
template<class Tool>
void VToolOptionsPropertyBrowser::SetName(VPE::VProperty *property)
{
if (auto *i = qgraphicsitem_cast<Tool *>(currentItem))
{
QString name = property->data(VPE::VProperty::DPC_Data, Qt::DisplayRole).toString();
if (name == i->name())
{
return;
}
i->setName(name);
}
else
{
qWarning()<<"Can't cast item";
}
}
//---------------------------------------------------------------------------------------------------------------------
template<class Tool>
void VToolOptionsPropertyBrowser::SetHold(VPE::VProperty *property)
{
if (auto *i = qgraphicsitem_cast<Tool *>(currentItem))
{
bool hold = property->data(VPE::VProperty::DPC_Data, Qt::DisplayRole).toBool();
if (hold == i->IsHold())
{
return;
}
i->SetHold(hold);
}
else
{
qWarning()<<"Can't cast item";
}
}
//---------------------------------------------------------------------------------------------------------------------
template<class Tool>
void VToolOptionsPropertyBrowser::SetVisible(VPE::VProperty *property)
{
if (auto *i = qgraphicsitem_cast<Tool *>(currentItem))
{
bool visible = property->data(VPE::VProperty::DPC_Data, Qt::DisplayRole).toBool();
if (visible == i->IsVisible())
{
return;
}
i->SetVisible(visible);
}
else
{
qWarning()<<"Can't cast item";
}
}
//---------------------------------------------------------------------------------------------------------------------
template<class Tool>
void VToolOptionsPropertyBrowser::SetPointName(VPE::VProperty *property)
@ -2513,6 +2607,54 @@ void VToolOptionsPropertyBrowser::ChangeDataToolEllipticalArc(VPE::VProperty *pr
}
}
//---------------------------------------------------------------------------------------------------------------------
void VToolOptionsPropertyBrowser::ChangeDataBackgroundPixmapItem(VPE::VProperty *property)
{
SCASSERT(property != nullptr)
const QString id = propertyToId[property];
switch (PropertiesList().indexOf(id))
{
case 0: // AttrName
SetName<VBackgroundPixmapItem>(property);
break;
case 65: // AttrHold
SetHold<VBackgroundPixmapItem>(property);
break;
case 66: // AttrVisible
SetVisible<VBackgroundPixmapItem>(property);
break;
default:
qWarning()<<"Unknown property type. id = "<<id;
break;
}
}
//---------------------------------------------------------------------------------------------------------------------
void VToolOptionsPropertyBrowser::ChangeDataBackgroundSVGItem(VPE::VProperty *property)
{
SCASSERT(property != nullptr)
const QString id = propertyToId[property];
switch (PropertiesList().indexOf(id))
{
case 0: // AttrName
SetName<VBackgroundSVGItem>(property);
break;
case 65: // AttrHold
SetHold<VBackgroundSVGItem>(property);
break;
case 66: // AttrVisible
SetVisible<VBackgroundSVGItem>(property);
break;
default:
qWarning()<<"Unknown property type. id = "<<id;
break;
}
}
//---------------------------------------------------------------------------------------------------------------------
void VToolOptionsPropertyBrowser::ShowOptionsToolSinglePoint(QGraphicsItem *item)
{
@ -3084,6 +3226,28 @@ void VToolOptionsPropertyBrowser::ShowOptionsToolEllipticalArc(QGraphicsItem *it
AddPropertyText(tr("Notes:"), i->GetNotes(), AttrNotes);
}
//---------------------------------------------------------------------------------------------------------------------
void VToolOptionsPropertyBrowser::ShowOptionsBackgroundPixmapItem(QGraphicsItem *item)
{
auto *i = qgraphicsitem_cast<VBackgroundPixmapItem *>(item);
formView->setTitle(tr("Background image"));
AddPropertyObjectName(i, tr("Name:"), false);
AddPropertyBool(tr("Hold:"), i->IsHold(), *AttrHold);
AddPropertyBool(tr("Visible:"), i->IsVisible(), *AttrVisible);
}
//---------------------------------------------------------------------------------------------------------------------
void VToolOptionsPropertyBrowser::ShowOptionsBackgroundSVGItem(QGraphicsItem *item)
{
auto *i = qgraphicsitem_cast<VBackgroundSVGItem *>(item);
formView->setTitle(tr("Background image"));
AddPropertyObjectName(i, tr("Name:"), false);
AddPropertyBool(tr("Hold:"), i->IsHold(), *AttrHold);
AddPropertyBool(tr("Visible:"), i->IsVisible(), *AttrVisible);
}
//---------------------------------------------------------------------------------------------------------------------
void VToolOptionsPropertyBrowser::UpdateOptionsToolSinglePoint()
{
@ -4028,6 +4192,26 @@ void VToolOptionsPropertyBrowser::UpdateOptionsToolEllipticalArc()
idToProperty[AttrAlias]->setValue(i->GetAliasSuffix());
}
//---------------------------------------------------------------------------------------------------------------------
void VToolOptionsPropertyBrowser::UpdateOptionsBackgroundPixmapItem()
{
auto *i = qgraphicsitem_cast<VBackgroundPixmapItem *>(currentItem);
idToProperty.value(AttrName)->setValue(i->name());
idToProperty.value(*AttrHold)->setValue(i->IsHold());
idToProperty.value(*AttrVisible)->setValue(i->IsVisible());
}
//---------------------------------------------------------------------------------------------------------------------
void VToolOptionsPropertyBrowser::UpdateOptionsBackgroundSVGItem()
{
auto *i = qgraphicsitem_cast<VBackgroundSVGItem *>(currentItem);
idToProperty.value(AttrName)->setValue(i->name());
idToProperty.value(*AttrHold)->setValue(i->IsHold());
idToProperty.value(*AttrVisible)->setValue(i->IsVisible());
}
//---------------------------------------------------------------------------------------------------------------------
QStringList VToolOptionsPropertyBrowser::PropertiesList() const
{
@ -4096,7 +4280,9 @@ QStringList VToolOptionsPropertyBrowser::PropertiesList() const
AttrNotes, /* 61 */
AttrAlias, /* 62 */
AttrAlias1, /* 63 */
AttrAlias2 /* 64 */
AttrAlias2, /* 64 */
*AttrHold, /* 65 */
*AttrVisible /* 66 */
};
return attr;
}

View file

@ -66,6 +66,15 @@ private:
void AddProperty(VPE::VProperty *property, const QString &id);
void ShowItemOptions(QGraphicsItem *item);
template<class Tool>
void SetName(VPE::VProperty *property);
template<class Tool>
void SetHold(VPE::VProperty *property);
template<class Tool>
void SetVisible(VPE::VProperty *property);
template<class Tool>
void SetPointName(VPE::VProperty *property);
@ -183,6 +192,7 @@ private:
void AddPropertyParentPointName(const QString &pointName, const QString &propertyName,
const QString &propertyAttribure);
void AddPropertyText(const QString &propertyName, const QString &text, const QString &attrName);
void AddPropertyBool(const QString &propertyName, bool value, const QString &attrName);
QStringList PropertiesList() const;
@ -220,6 +230,8 @@ private:
void ChangeDataToolFlippingByLine(VPE::VProperty *property);
void ChangeDataToolFlippingByAxis(VPE::VProperty *property);
void ChangeDataToolEllipticalArc(VPE::VProperty *property);
void ChangeDataBackgroundPixmapItem(VPE::VProperty *property);
void ChangeDataBackgroundSVGItem(VPE::VProperty *property);
void ShowOptionsToolSinglePoint(QGraphicsItem *item);
void ShowOptionsToolEndLine(QGraphicsItem *item);
@ -255,6 +267,8 @@ private:
void ShowOptionsToolFlippingByLine(QGraphicsItem *item);
void ShowOptionsToolFlippingByAxis(QGraphicsItem *item);
void ShowOptionsToolEllipticalArc(QGraphicsItem *item);
void ShowOptionsBackgroundPixmapItem(QGraphicsItem *item);
void ShowOptionsBackgroundSVGItem(QGraphicsItem *item);
void UpdateOptionsToolSinglePoint();
void UpdateOptionsToolEndLine();
@ -290,6 +304,8 @@ private:
void UpdateOptionsToolFlippingByLine();
void UpdateOptionsToolFlippingByAxis();
void UpdateOptionsToolEllipticalArc();
void UpdateOptionsBackgroundPixmapItem();
void UpdateOptionsBackgroundSVGItem();
};
#endif // VTOOLOPTIONSPROPERTYBROWSER_H

View file

@ -0,0 +1,55 @@
/************************************************************************
**
** @file dialogaddbackgroundimage.cpp
** @author Roman Telezhynskyi <dismine(at)gmail.com>
** @date 21 1, 2022
**
** @brief
** @copyright
** This source code is part of the Valentina project, a pattern making
** program, whose allow create and modeling patterns of clothing.
** Copyright (C) 2022 Valentina project
** <https://gitlab.com/smart-pattern/valentina> All Rights Reserved.
**
** Valentina is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Valentina 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
**
*************************************************************************/
#include "dialogaddbackgroundimage.h"
#include "ui_dialogaddbackgroundimage.h"
//---------------------------------------------------------------------------------------------------------------------
DialogAddBackgroundImage::DialogAddBackgroundImage(QWidget *parent) :
QDialog(parent),
ui(new Ui::DialogAddBackgroundImage)
{
ui->setupUi(this);
}
//---------------------------------------------------------------------------------------------------------------------
DialogAddBackgroundImage::~DialogAddBackgroundImage()
{
delete ui;
}
//---------------------------------------------------------------------------------------------------------------------
auto DialogAddBackgroundImage::Name() const -> QString
{
return ui->lineEditName->text();
}
//---------------------------------------------------------------------------------------------------------------------
auto DialogAddBackgroundImage::BuiltIn() const -> bool
{
return ui->checkBoxBuiltIn->isChecked();
}

View file

@ -0,0 +1,58 @@
/************************************************************************
**
** @file dialogaddbackgroundimage.h
** @author Roman Telezhynskyi <dismine(at)gmail.com>
** @date 21 1, 2022
**
** @brief
** @copyright
** This source code is part of the Valentina project, a pattern making
** program, whose allow create and modeling patterns of clothing.
** Copyright (C) 2022 Valentina project
** <https://gitlab.com/smart-pattern/valentina> All Rights Reserved.
**
** Valentina is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Valentina 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
**
*************************************************************************/
#ifndef DIALOGADDBACKGROUNDIMAGE_H
#define DIALOGADDBACKGROUNDIMAGE_H
#include <QDialog>
#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
#include "../vmisc/defglobal.h"
#endif // QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
namespace Ui
{
class DialogAddBackgroundImage;
}
class DialogAddBackgroundImage : public QDialog
{
Q_OBJECT
public:
explicit DialogAddBackgroundImage(QWidget *parent = nullptr);
~DialogAddBackgroundImage() override;
auto Name() const -> QString;
auto BuiltIn() const -> bool;
private:
Q_DISABLE_COPY_MOVE(DialogAddBackgroundImage)
Ui::DialogAddBackgroundImage *ui;
};
#endif // DIALOGADDBACKGROUNDIMAGE_H

View file

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DialogAddBackgroundImage</class>
<widget class="QDialog" name="DialogAddBackgroundImage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>204</width>
<height>105</height>
</rect>
</property>
<property name="windowTitle">
<string>Background image</string>
</property>
<property name="windowIcon">
<iconset resource="../../../libs/vmisc/share/resources/icon.qrc">
<normaloff>:/icon/64x64/icon64x64.png</normaloff>:/icon/64x64/icon64x64.png</iconset>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Name:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditName"/>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="checkBoxBuiltIn">
<property name="toolTip">
<string>Determine should an image built in or added as path to the file.</string>
</property>
<property name="text">
<string>Built in</string>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../../../libs/vmisc/share/resources/icon.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>DialogAddBackgroundImage</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DialogAddBackgroundImage</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View file

@ -233,7 +233,7 @@ QT_WARNING_DISABLE_GCC("-Wswitch-default")
HistoryRecord DialogHistory::Record(const VToolRecord &tool) const
{
// This check helps to find missed tools in the switch
Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55, "Not all tools were used in history.");
Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 59, "Not all tools were used in history.");
HistoryRecord record;
record.id = tool.getId();
@ -257,6 +257,10 @@ HistoryRecord DialogHistory::Record(const VToolRecord &tool) const
case Tool::Cut:
case Tool::Midpoint:// Same as Tool::AlongLine, but tool will never has such type
case Tool::ArcIntersectAxis:// Same as Tool::CurveIntersectAxis, but tool will never has such type
case Tool::BackgroundImage:
case Tool::BackgroundImageControls:
case Tool::BackgroundPixmapImage:
case Tool::BackgroundSVGImage:
case Tool::LAST_ONE_DO_NOT_USE:
Q_UNREACHABLE(); //-V501
break;

View file

@ -50,6 +50,7 @@
#include "../vmisc/vvalentinasettings.h"
#include "../qmuparser/qmudef.h"
#include "../ifc/xml/vpatternimage.h"
#include "../ifc/xml/utils.h"
//---------------------------------------------------------------------------------------------------------------------
DialogPatternProperties::DialogPatternProperties(VPattern *doc, VContainer *pattern, QWidget *parent)
@ -327,33 +328,9 @@ void DialogPatternProperties::InitImage()
//---------------------------------------------------------------------------------------------------------------------
void DialogPatternProperties::ChangeImage()
{
auto PrepareFilter = []()
{
const QList<QByteArray> supportedFormats = QImageReader::supportedImageFormats();
const QSet<QString> filterFormats{"bmp", "jpeg", "jpg", "png", "svg", "svgz", "tif", "tiff", "webp"};
QStringList sufixes;
for (const auto& format : supportedFormats)
{
if (filterFormats.contains(format))
{
sufixes.append(QStringLiteral("*.%1").arg(QString(format)));
}
}
QStringList filters;
if (not sufixes.isEmpty())
{
filters.append(tr("Images") + QStringLiteral(" (%1)").arg(sufixes.join(' ')));
}
filters.append(tr("All files") + QStringLiteral(" (*.*)"));
return filters.join(QStringLiteral(";;"));
};
const QString fileName = QFileDialog::getOpenFileName(this, tr("Image for pattern"), QString(), PrepareFilter(),
nullptr, VAbstractApplication::VApp()->NativeFileDialog());
const QString fileName = QFileDialog::getOpenFileName(this, tr("Image for pattern"), QString(),
PrepareImageFilters(), nullptr,
VAbstractApplication::VApp()->NativeFileDialog());
if (not fileName.isEmpty())
{
VPatternImage image = VPatternImage::FromFile(fileName);

View file

@ -2,6 +2,7 @@
# This need for corect working file translations.pro
HEADERS += \
$$PWD/dialogaddbackgroundimage.h \
$$PWD/dialogs.h \
$$PWD/dialogincrements.h \
$$PWD/dialoghistory.h \
@ -11,6 +12,7 @@ HEADERS += \
$$PWD/dialoglayoutsettings.h \
$$PWD/dialoglayoutprogress.h \
$$PWD/dialogsavelayout.h \
$$PWD/vwidgetbackgroundimages.h \
$$PWD/vwidgetgroups.h \
$$PWD/vwidgetdetails.h \
$$PWD/dialogpreferences.h \
@ -22,6 +24,7 @@ HEADERS += \
$$PWD/dialogfinalmeasurements.h
SOURCES += \
$$PWD/dialogaddbackgroundimage.cpp \
$$PWD/dialogincrements.cpp \
$$PWD/dialoghistory.cpp \
$$PWD/dialogpatternproperties.cpp \
@ -30,6 +33,7 @@ SOURCES += \
$$PWD/dialoglayoutsettings.cpp \
$$PWD/dialoglayoutprogress.cpp \
$$PWD/dialogsavelayout.cpp \
$$PWD/vwidgetbackgroundimages.cpp \
$$PWD/vwidgetgroups.cpp \
$$PWD/vwidgetdetails.cpp \
$$PWD/dialogpreferences.cpp \
@ -41,6 +45,7 @@ SOURCES += \
$$PWD/dialogfinalmeasurements.cpp
FORMS += \
$$PWD/dialogaddbackgroundimage.ui \
$$PWD/dialogincrements.ui \
$$PWD/dialoghistory.ui \
$$PWD/dialogpatternproperties.ui \
@ -49,6 +54,7 @@ FORMS += \
$$PWD/dialoglayoutsettings.ui \
$$PWD/dialoglayoutprogress.ui \
$$PWD/dialogsavelayout.ui \
$$PWD/vwidgetbackgroundimages.ui \
$$PWD/vwidgetgroups.ui \
$$PWD/vwidgetdetails.ui \
$$PWD/dialogpreferences.ui \

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,112 @@
/************************************************************************
**
** @file vwidgetbackgroundimages.h
** @author Roman Telezhynskyi <dismine(at)gmail.com>
** @date 26 1, 2022
**
** @brief
** @copyright
** This source code is part of the Valentina project, a pattern making
** program, whose allow create and modeling patterns of clothing.
** Copyright (C) 2022 Valentina project
** <https://gitlab.com/smart-pattern/valentina> All Rights Reserved.
**
** Valentina is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Valentina 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
**
*************************************************************************/
#ifndef VWIDGETBACKGROUNDIMAGES_H
#define VWIDGETBACKGROUNDIMAGES_H
#include <QWidget>
#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
#include "../vmisc/defglobal.h"
#endif // QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
#include "../vmisc/def.h"
class VAbstractPattern;
class VBackgroundPatternImage;
namespace Ui
{
class VWidgetBackgroundImages;
}
enum class ScaleUnit {Percent, Mm, Cm, Inch, Px};
class VWidgetBackgroundImages : public QWidget
{
Q_OBJECT
public:
explicit VWidgetBackgroundImages(VAbstractPattern *doc, QWidget *parent = nullptr);
~VWidgetBackgroundImages() override;
signals:
void DeleteImage(const QUuid &id);
void SelectImage(const QUuid &id);
public slots:
void UpdateImages();
void UpdateImage(const QUuid &id);
void ImageSelected(const QUuid &id);
private slots:
void ImageHoldChanged(int row, int column);
void ImageVisibilityChanged(int row, int column);
void ImageNameChanged(int row, int column);
void ContextMenu(const QPoint &pos);
void CurrentImageChanged(int currentRow, int currentColumn, int previousRow, int previousColumn);
void MoveImageOnTop();
void MoveImageUp();
void MoveImageDown();
void MoveImageBottom();
void ApplyImageTransformation();
void ResetImageTransformationSettings();
void RelativeTranslationChanged(bool checked);
void ScaleProportionallyChanged(bool checked);
void ScaleWidthChanged(double value);
void ScaleHeightChanged(double value);
void ImagePositionChanged(const QUuid &id);
private:
Q_DISABLE_COPY_MOVE(VWidgetBackgroundImages)
Ui::VWidgetBackgroundImages *ui;
VAbstractPattern *m_doc;
Unit m_oldImageTranslationUnit{Unit::Mm};
ScaleUnit m_oldImageScaleUnit{ScaleUnit::Percent};
void FillTable(const QVector<VBackgroundPatternImage> &images);
void ToggleImageHold(const QUuid &id) const;
void ToggleImageVisibility(const QUuid &id) const;
Q_REQUIRED_RESULT auto ImageRow(const QUuid &id) const -> int;
Q_REQUIRED_RESULT auto CurrentTranslateUnit() const -> Unit;
Q_REQUIRED_RESULT auto CurrentScaleUnit() const -> ScaleUnit;
void InitImageTranslation();
Q_REQUIRED_RESULT auto ImageWidth() const -> qreal;
Q_REQUIRED_RESULT auto ImageHeight() const -> qreal;
Q_REQUIRED_RESULT auto WidthScaleUnitConvertor(qreal value, enum ScaleUnit from, enum ScaleUnit to) const -> qreal;
Q_REQUIRED_RESULT auto HeightScaleUnitConvertor(qreal value, enum ScaleUnit from, enum ScaleUnit to) const -> qreal;
void SetAbsolutePisition(const QUuid &id);
};
#endif // VWIDGETBACKGROUNDIMAGES_H

View file

@ -0,0 +1,418 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>VWidgetBackgroundImages</class>
<widget class="QWidget" name="VWidgetBackgroundImages">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>401</width>
<height>640</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>381</width>
<height>620</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QGroupBox" name="groupBoxPieceTransformation">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Transformation</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_25">
<item>
<widget class="QTabWidget" name="tabWidgetImageTransformation">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tabTranslate">
<attribute name="title">
<string comment="Translate piece">Translate</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="labelCurrentPieceTranslateX">
<property name="text">
<string>Horizontal:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBoxImageHorizontalTranslate">
<property name="minimum">
<double>-10000.000000000000000</double>
</property>
<property name="maximum">
<double>10000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QComboBox" name="comboBoxTranslateUnit"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelCurrentPieceTranslateY">
<property name="text">
<string>Vertical:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBoxImageVerticalTranslate">
<property name="minimum">
<double>-10000.000000000000000</double>
</property>
<property name="maximum">
<double>10000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="checkBoxRelativeTranslation">
<property name="text">
<string>Relative translation</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabScale">
<attribute name="title">
<string>Scale</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="labelImageScaleWidth">
<property name="text">
<string>Width:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBoxScaleWidth">
<property name="minimum">
<double>-10000.000000000000000</double>
</property>
<property name="maximum">
<double>10000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QComboBox" name="comboBoxScaleUnit"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelImageScaleHeight">
<property name="text">
<string>Height:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBoxScaleHeight">
<property name="minimum">
<double>-10000.000000000000000</double>
</property>
<property name="maximum">
<double>10000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="checkBoxScaleProportionally">
<property name="text">
<string>Scale proportionally</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabRotate">
<attribute name="title">
<string>Rotate</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_24">
<item>
<widget class="QGroupBox" name="groupBoxCurrentPieceRotation">
<property name="title">
<string>Rotation</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="3">
<widget class="QToolButton" name="toolButtonImageRotationClockwise">
<property name="text">
<string notr="true"/>
</property>
<property name="icon">
<iconset theme="object-rotate-right">
<normaloff>../../puzzle</normaloff>../../puzzle</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup</string>
</attribute>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBoxRotationAngle">
<property name="suffix">
<string notr="true">°</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>-360.000000000000000</double>
</property>
<property name="maximum">
<double>360.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="0" column="4">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="2">
<widget class="QToolButton" name="toolButtonImageRotationAnticlockwise">
<property name="text">
<string notr="true"/>
</property>
<property name="icon">
<iconset theme="object-rotate-left">
<normaloff>../../puzzle</normaloff>../../puzzle</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup</string>
</attribute>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="labelCurrentPieceAngle">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Angle:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Apply|QDialogButtonBox::Reset</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Z Value</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QToolButton" name="toolButtonBottom">
<property name="text">
<string notr="true">...</string>
</property>
<property name="icon">
<iconset theme="go-bottom"/>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="toolButtonDown">
<property name="text">
<string notr="true">...</string>
</property>
<property name="icon">
<iconset theme="go-down"/>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="toolButtonUp">
<property name="text">
<string notr="true">...</string>
</property>
<property name="icon">
<iconset theme="go-up"/>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="toolButtonTop">
<property name="text">
<string notr="true">...</string>
</property>
<property name="icon">
<iconset theme="go-top"/>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QTableWidget" name="tableWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>1</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<attribute name="horizontalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="horizontalHeaderMinimumSectionSize">
<number>16</number>
</attribute>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderMinimumSectionSize">
<number>10</number>
</attribute>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
<buttongroups>
<buttongroup name="buttonGroup"/>
</buttongroups>
</ui>

View file

@ -61,6 +61,7 @@
#include "dialogs/vwidgetgroups.h"
#include "../vtools/undocommands/undogroup.h"
#include "dialogs/vwidgetdetails.h"
#include "dialogs/dialogaddbackgroundimage.h"
#include "../vpatterndb/vpiecepath.h"
#include "../qmuparser/qmuparsererror.h"
#include "../vtools/dialogs/support/dialogeditlabel.h"
@ -71,6 +72,15 @@
#include "../vwidgets/vgraphicssimpletextitem.h"
#include "../vlayout/dialogs/dialoglayoutscale.h"
#include "../vmisc/dialogs/dialogselectlanguage.h"
#include "../ifc/xml/vbackgroundpatternimage.h"
#include "../vtools/tools/backgroundimage/vbackgroundimageitem.h"
#include "../vtools/tools/backgroundimage/vbackgroundpixmapitem.h"
#include "../vtools/tools/backgroundimage/vbackgroundsvgitem.h"
#include "../vtools/tools/backgroundimage/vbackgroundimagecontrols.h"
#include "../vtools/undocommands/image/addbackgroundimage.h"
#include "../vtools/undocommands/image/deletebackgroundimage.h"
#include "../ifc/xml/utils.h"
#include "dialogs/vwidgetbackgroundimages.h"
#if QT_VERSION < QT_VERSION_CHECK(5, 12, 0)
#include "../vmisc/backport/qscopeguard.h"
@ -104,6 +114,8 @@
#include <QFuture>
#include <QtConcurrent>
#include <QStyleFactory>
#include <QImageReader>
#include <QUuid>
#if defined(Q_OS_WIN32) && QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
#include <QWinTaskbarButton>
@ -250,6 +262,8 @@ MainWindow::MainWindow(QWidget *parent)
ToolBarStages();
InitToolButtons();
connect(ui->actionAddBackgroundImage, &QAction::triggered, this, &MainWindow::ActionAddBackgroundImage);
m_progressBar->setVisible(false);
#if defined(Q_OS_WIN32) && QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
m_taskbarProgress->setVisible(false);
@ -495,6 +509,7 @@ void MainWindow::InitScenes()
connect(this, &MainWindow::EnableSplinePathHover, sceneDraw, &VMainGraphicsScene::ToggleSplinePathHover);
connect(sceneDraw, &VMainGraphicsScene::mouseMove, this, &MainWindow::MouseMove);
connect(sceneDraw, &VMainGraphicsScene::AddBackgroundImage, this, &MainWindow::PlaceBackgroundImage);
sceneDetails = new VMainGraphicsScene(this);
connect(this, &MainWindow::EnableItemMove, sceneDetails, &VMainGraphicsScene::EnableItemMove);
@ -662,7 +677,7 @@ void MainWindow::SetToolButton(bool checked, Tool t, const QString &cursor, cons
dialogTool = new Dialog(pattern, 0, this);
// This check helps to find missed tools in the switch
Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55, "Check if need to extend.");
Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 59, "Check if need to extend.");
switch(t)
{
@ -1364,6 +1379,50 @@ void MainWindow::ZoomFitBestCurrent()
}
}
//---------------------------------------------------------------------------------------------------------------------
void MainWindow::PlaceBackgroundImage(const QPointF &pos, const QString &fileName)
{
DialogAddBackgroundImage dialog(this);
if (dialog.exec() == QDialog::Rejected)
{
qCritical() << tr("Unable to add background image");
return;
}
VBackgroundPatternImage image = VBackgroundPatternImage::FromFile(fileName, dialog.BuiltIn());
image.SetName(dialog.Name());
QTransform m;
m.translate(pos.x(), pos.y());
QTransform imageMatrix = image.Matrix();
imageMatrix *= m;
image.SetMatrix(m);
if (not image.IsValid())
{
qCritical() << tr("Invalid image. Error: %1").arg(image.ErrorString());
return;
}
auto* addBackgroundImage = new AddBackgroundImage(image, doc);
connect(addBackgroundImage, &AddBackgroundImage::AddItem, this, &MainWindow::AddBackgroundImageItem);
connect(addBackgroundImage, &AddBackgroundImage::DeleteItem, this, &MainWindow::DeleteBackgroundImageItem);
VApplication::VApp()->getUndoStack()->push(addBackgroundImage);
}
//---------------------------------------------------------------------------------------------------------------------
void MainWindow::RemoveBackgroundImage(const QUuid &id)
{
VBackgroundPatternImage image = doc->GetBackgroundImage(id);
auto* deleteBackgroundImage = new DeleteBackgroundImage(image, doc);
connect(deleteBackgroundImage, &DeleteBackgroundImage::AddItem, this, &MainWindow::AddBackgroundImageItem);
connect(deleteBackgroundImage, &DeleteBackgroundImage::DeleteItem, this, &MainWindow::DeleteBackgroundImageItem);
VApplication::VApp()->getUndoStack()->push(deleteBackgroundImage);
}
//---------------------------------------------------------------------------------------------------------------------
/**
* @brief ToolCutArc handler tool cutArc.
@ -2302,7 +2361,7 @@ void MainWindow::ExportDraw(const QString &fileName)
// Restore scale, scrollbars and current active pattern piece
ui->view->setTransform(viewTransform);
VMainGraphicsView::NewSceneRect(ui->view->scene(), ui->view);
emit ScaleChanged(ui->view->transform().m11());
ScaleChanged(ui->view->transform().m11());
ui->view->verticalScrollBar()->setValue(verticalScrollBarValue);
ui->view->horizontalScrollBar()->setValue(horizontalScrollBarValue);
@ -2310,6 +2369,70 @@ void MainWindow::ExportDraw(const QString &fileName)
doc->ChangeActivPP(doc->GetNameActivPP(), Document::FullParse);
}
//---------------------------------------------------------------------------------------------------------------------
void MainWindow::NewBackgroundImageItem(const VBackgroundPatternImage &image)
{
if (m_backgroudcontrols == nullptr)
{
m_backgroudcontrols = new VBackgroundImageControls(doc);
connect(sceneDraw, &VMainGraphicsScene::ItemByMouseRelease, m_backgroudcontrols,
&VBackgroundImageControls::DeactivateControls);
sceneDraw->addItem(m_backgroudcontrols);
}
if (m_backgroundImages.contains(image.Id()))
{
VBackgroundImageItem *item = m_backgroundImages.value(image.Id());
if (item != nullptr)
{
item->SetImage(image);
}
}
else if (m_deletedBackgroundImageItems.contains(image.Id()))
{
VBackgroundImageItem *item = m_deletedBackgroundImageItems.value(image.Id());
if (item != nullptr)
{
item->SetImage(image);
sceneDraw->addItem(item);
m_backgroundImages.insert(image.Id(), item);
}
m_deletedBackgroundImageItems.remove(image.Id());
}
else
{
VBackgroundImageItem *item = nullptr;
if (image.Type() == PatternImage::Raster)
{
item = new VBackgroundPixmapItem(image, doc);
}
else if (image.Type() == PatternImage::Vector || image.Type() == PatternImage::Unknown)
{
item = new VBackgroundSVGItem(image, doc);
}
if (item != nullptr)
{
connect(item, &VBackgroundImageItem::UpdateControls, m_backgroudcontrols,
&VBackgroundImageControls::UpdateControls);
connect(item, &VBackgroundImageItem::ActivateControls, m_backgroudcontrols,
&VBackgroundImageControls::ActivateControls);
connect(item, &VBackgroundImageItem::DeleteImage, this, &MainWindow::RemoveBackgroundImage);
connect(this, &MainWindow::EnableBackgroundImageSelection, item, &VBackgroundImageItem::EnableSelection);
connect(item, &VBackgroundImageItem::ShowImageInExplorer, this, &MainWindow::ShowBackgroundImageInExplorer);
connect(item, &VBackgroundImageItem::SaveImage, this, &MainWindow::SaveBackgroundImage);
connect(m_backgroudcontrols, &VBackgroundImageControls::ActiveImageChanged, backgroundImagesWidget,
&VWidgetBackgroundImages::ImageSelected);
connect(backgroundImagesWidget, &VWidgetBackgroundImages::SelectImage, m_backgroudcontrols,
&VBackgroundImageControls::ActivateControls);
sceneDraw->addItem(item);
m_backgroundImages.insert(image.Id(), item);
}
}
VMainGraphicsView::NewSceneRect(sceneDraw, ui->view);
}
//---------------------------------------------------------------------------------------------------------------------
#if defined(Q_OS_MAC)
void MainWindow::OpenAt(QAction *where)
@ -2543,7 +2666,7 @@ void MainWindow::InitToolButtons()
}
// This check helps to find missed tools
Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55, "Check if all tools were connected.");
Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 59, "Check if all tools were connected.");
connect(ui->toolButtonEndLine, &QToolButton::clicked, this, &MainWindow::ToolEndLine);
connect(ui->toolButtonLine, &QToolButton::clicked, this, &MainWindow::ToolLine);
@ -2622,7 +2745,7 @@ QT_WARNING_DISABLE_GCC("-Wswitch-default")
void MainWindow::CancelTool()
{
// This check helps to find missed tools in the switch
Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55, "Not all tools were handled.");
Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 59, "Not all tools were handled.");
qCDebug(vMainWindow, "Canceling tool.");
if(not dialogTool.isNull())
@ -2664,6 +2787,10 @@ void MainWindow::CancelTool()
case Tool::NodeElArc:
case Tool::NodeSpline:
case Tool::NodeSplinePath:
case Tool::BackgroundImage:
case Tool::BackgroundImageControls:
case Tool::BackgroundPixmapImage:
case Tool::BackgroundSVGImage:
Q_UNREACHABLE(); //-V501
//Nothing to do here because we can't create this tool from main window.
break;
@ -2837,6 +2964,7 @@ void MainWindow::ArrowTool(bool checked)
emit EnableNodeLabelSelection(true);
emit EnableNodePointSelection(true);
emit EnableDetailSelection(true);// Disable when done visualization details
emit EnableBackgroundImageSelection(true);
// Hovering
emit EnableLabelHover(true);
@ -2849,6 +2977,7 @@ void MainWindow::ArrowTool(bool checked)
emit EnableNodeLabelHover(true);
emit EnableNodePointHover(true);
emit EnableDetailHover(true);
emit EnableImageBackgroundHover(true);
ui->view->AllowRubberBand(true);
ui->view->viewport()->unsetCursor();
@ -2967,12 +3096,14 @@ void MainWindow::ActionDraw(bool checked)
}
ui->dockWidgetLayoutPages->setVisible(false);
ui->dockWidgetToolOptions->setVisible(isDockToolOptionsVisible);
ui->dockWidgetToolOptions->setVisible(m_toolOptionsActive);
ui->dockWidgetGroups->setWidget(groupsWidget);
ui->dockWidgetGroups->setWindowTitle(tr("Groups of visibility"));
ui->dockWidgetGroups->setVisible(isDockGroupsVisible);
ui->dockWidgetGroups->setVisible(m_groupsActive);
ui->dockWidgetGroups->setToolTip(tr("Contains all visibility groups"));
ui->dockWidgetBackgroundImages->setVisible(m_backgroundImagesActive);
}
else
{
@ -3045,10 +3176,11 @@ void MainWindow::ActionDetails(bool checked)
ui->dockWidgetGroups->setWidget(detailsWidget);
ui->dockWidgetGroups->setWindowTitle(tr("Details"));
ui->dockWidgetGroups->setVisible(isDockGroupsVisible);
ui->dockWidgetGroups->setVisible(m_groupsActive);
ui->dockWidgetGroups->setToolTip(tr("Show which details will go in layout"));
ui->dockWidgetToolOptions->setVisible(isDockToolOptionsVisible);
ui->dockWidgetToolOptions->setVisible(m_toolOptionsActive);
ui->dockWidgetBackgroundImages->setVisible(false);
m_statusLabel->setText(QString());
@ -3159,14 +3291,9 @@ void MainWindow::ActionLayout(bool checked)
}
ui->dockWidgetLayoutPages->setVisible(true);
ui->dockWidgetToolOptions->blockSignals(true);
ui->dockWidgetToolOptions->setVisible(false);
ui->dockWidgetToolOptions->blockSignals(false);
ui->dockWidgetGroups->blockSignals(true);
ui->dockWidgetGroups->setVisible(false);
ui->dockWidgetGroups->blockSignals(false);
ui->dockWidgetBackgroundImages->setVisible(false);
ShowPaper(ui->listWidget->currentRow());
@ -3548,6 +3675,18 @@ void MainWindow::on_actionUpdateManualLayout_triggered()
}
}
//---------------------------------------------------------------------------------------------------------------------
void MainWindow::ActionAddBackgroundImage()
{
const QString fileName = QFileDialog::getOpenFileName(this, tr("Select background image"), QString(),
PrepareImageFilters(), nullptr,
VAbstractApplication::VApp()->NativeFileDialog());
if (not fileName.isEmpty())
{
PlaceBackgroundImage(QPointF(), fileName);
}
}
//---------------------------------------------------------------------------------------------------------------------
/**
* @brief Clear reset to default window.
@ -3570,8 +3709,10 @@ void MainWindow::Clear()
UpdateWindowTitle();
UpdateVisibilityGroups();
detailsWidget->UpdateList();
backgroundImagesWidget->UpdateImages();
qCDebug(vMainWindow, "Clearing scenes.");
sceneDraw->clear();
sceneDraw->SetAcceptDrop(false);
sceneDetails->clear();
ArrowTool(true);
comboBoxDraws->clear();
@ -3603,6 +3744,7 @@ void MainWindow::Clear()
ui->actionEditCurrent->setEnabled(false);
ui->actionPreviousPatternPiece->setEnabled(false);
ui->actionNextPatternPiece->setEnabled(false);
ui->actionAddBackgroundImage->setEnabled(false);
SetEnableTool(false);
VAbstractValApplication::VApp()->SetPatternUnits(Unit::Cm);
VAbstractValApplication::VApp()->SetMeasurementsType(MeasurementsType::Unknown);
@ -3985,6 +4127,7 @@ void MainWindow::SetEnableWidgets(bool enable)
ui->actionUnloadMeasurements->setEnabled(enable && designStage);
ui->actionPreviousPatternPiece->setEnabled(enable && drawStage);
ui->actionNextPatternPiece->setEnabled(enable && drawStage);
ui->actionAddBackgroundImage->setEnabled(enable && drawStage);
ui->actionIncreaseLabelFont->setEnabled(enable);
ui->actionDecreaseLabelFont->setEnabled(enable);
ui->actionOriginalLabelFont->setEnabled(enable);
@ -3998,6 +4141,7 @@ void MainWindow::SetEnableWidgets(bool enable)
actionDockWidgetToolOptions->setEnabled(enable && designStage);
actionDockWidgetGroups->setEnabled(enable && designStage);
actionDockWidgetBackgroundImages->setEnabled(enable && drawStage);
undoAction->setEnabled(enable && designStage && VAbstractApplication::VApp()->getUndoStack()->canUndo());
redoAction->setEnabled(enable && designStage && VAbstractApplication::VApp()->getUndoStack()->canRedo());
@ -4189,6 +4333,98 @@ void MainWindow::SetDefaultGUILanguage()
}
}
//---------------------------------------------------------------------------------------------------------------------
void MainWindow::AddBackgroundImageItem(const QUuid &id)
{
NewBackgroundImageItem(doc->GetBackgroundImage(id));
if (backgroundImagesWidget != nullptr)
{
backgroundImagesWidget->UpdateImages();
}
}
//---------------------------------------------------------------------------------------------------------------------
void MainWindow::DeleteBackgroundImageItem(const QUuid &id)
{
if (m_backgroundImages.contains(id))
{
VBackgroundImageItem *item = m_backgroundImages.value(id);
emit ui->view->itemClicked(nullptr); // Hide visualization to avoid a crash
sceneDraw->removeItem(item);
if (m_backgroudcontrols != nullptr && m_backgroudcontrols->Id() == id)
{
m_backgroudcontrols->ActivateControls(QUuid());
}
m_backgroundImages.remove(id);
m_deletedBackgroundImageItems.insert(id, item);
if (backgroundImagesWidget != nullptr)
{
backgroundImagesWidget->UpdateImages();
}
}
}
//---------------------------------------------------------------------------------------------------------------------
void MainWindow::ShowBackgroundImageInExplorer(const QUuid &id)
{
ShowInGraphicalShell(doc->GetBackgroundImage(id).FilePath());
}
//---------------------------------------------------------------------------------------------------------------------
void MainWindow::SaveBackgroundImage(const QUuid &id)
{
VBackgroundPatternImage image = doc->GetBackgroundImage(id);
if (not image.IsValid())
{
qCritical() << tr("Unable to save image. Error: %1").arg(image.ErrorString());
return;
}
if (image.ContentData().isEmpty())
{
qCritical() << tr("Unable to save image. No data.");
return;
}
const QByteArray imageData = QByteArray::fromBase64(image.ContentData());
QMimeType mime = MimeTypeFromByteArray(imageData);
QString path = QDir::homePath() + QDir::separator() + tr("untitled");
QStringList filters;
if (mime.isValid())
{
QStringList suffixes = mime.suffixes();
if (not suffixes.isEmpty())
{
path += '.' + suffixes.at(0);
}
filters.append(mime.filterString());
}
filters.append(tr("All files") + QStringLiteral(" (*.*)"));
QString filter = filters.join(QStringLiteral(";;"));
QString filename = QFileDialog::getSaveFileName(this, tr("Save Image"), path, filter, nullptr,
VAbstractApplication::VApp()->NativeFileDialog());
if (not filename.isEmpty())
{
QFile file(filename);
if (file.open(QIODevice::WriteOnly))
{
file.write(imageData);
}
else
{
qCritical() << tr("Unable to save image. Error: %1").arg(file.errorString());
}
}
}
//---------------------------------------------------------------------------------------------------------------------
void MainWindow::InitDimensionControls()
{
@ -4396,7 +4632,7 @@ QT_WARNING_DISABLE_GCC("-Wswitch-default")
QT_WARNING_POP
// This check helps to find missed tools
Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55, "Not all tools were handled.");
Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 59, "Not all tools were handled.");
//Drawing Tools
ui->toolButtonEndLine->setEnabled(drawTools);
@ -4593,9 +4829,15 @@ void MainWindow::ReadSettings()
restoreState(settings->GetWindowState());
restoreState(settings->GetToolbarsState(), AppVersion());
ui->dockWidgetGroups->setVisible(settings->IsDockWidgetGroupsActive());
ui->dockWidgetToolOptions->setVisible(settings->IsDockWidgetToolOptionsActive());
ui->dockWidgetMessages->setVisible(settings->IsDockWidgetPatternMessagesActive());
m_groupsActive = settings->IsDockWidgetGroupsActive();
m_toolOptionsActive = settings->IsDockWidgetToolOptionsActive();
m_patternMessagesActive = settings->IsDockWidgetPatternMessagesActive();
m_backgroundImagesActive = settings->IsDockWidgetBackgroundImagesActive();
ui->dockWidgetGroups->setVisible(m_groupsActive);
ui->dockWidgetToolOptions->setVisible(m_toolOptionsActive);
ui->dockWidgetMessages->setVisible(m_patternMessagesActive);
ui->dockWidgetBackgroundImages->setVisible(m_backgroundImagesActive);
// Scene antialiasing
ui->view->SetAntialiasing(settings->GetGraphicalOutput());
@ -4609,9 +4851,6 @@ void MainWindow::ReadSettings()
// Tool box scaling
ToolBoxSizePolicy();
isDockToolOptionsVisible = ui->dockWidgetToolOptions->isEnabled();
isDockGroupsVisible = ui->dockWidgetGroups->isEnabled();
QFont f = ui->plainTextEditPatternMessages->font();
f.setPointSize(settings->GetPatternMessageFontSize(f.pointSize()));
ui->plainTextEditPatternMessages->setFont(f);
@ -4635,9 +4874,10 @@ void MainWindow::WriteSettings()
settings->SetWindowState(saveState());
settings->SetToolbarsState(saveState(AppVersion()));
settings->SetDockWidgetGroupsActive(ui->dockWidgetGroups->isEnabled());
settings->SetDockWidgetToolOptionsActive(ui->dockWidgetToolOptions->isEnabled());
settings->SetDockWidgetPatternMessagesActive(ui->dockWidgetMessages->isEnabled());
settings->SetDockWidgetGroupsActive(ui->dockWidgetGroups->isVisible());
settings->SetDockWidgetToolOptionsActive(ui->dockWidgetToolOptions->isVisible());
settings->SetDockWidgetPatternMessagesActive(ui->dockWidgetMessages->isVisible());
settings->SetDockWidgetBackgroundImagesActive(actionDockWidgetBackgroundImages->isChecked());
settings->sync();
if (settings->status() == QSettings::AccessError)
@ -4734,7 +4974,7 @@ QT_WARNING_DISABLE_GCC("-Wswitch-default")
void MainWindow::LastUsedTool()
{
// This check helps to find missed tools in the switch
Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55, "Not all tools were handled.");
Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 59, "Not all tools were handled.");
if (currentTool == lastUsedTool)
{
@ -4762,6 +5002,10 @@ void MainWindow::LastUsedTool()
case Tool::NodeElArc:
case Tool::NodeSpline:
case Tool::NodeSplinePath:
case Tool::BackgroundImage:
case Tool::BackgroundImageControls:
case Tool::BackgroundPixmapImage:
case Tool::BackgroundSVGImage:
Q_UNREACHABLE(); //-V501
//Nothing to do here because we can't create this tool from main window.
break;
@ -4949,20 +5193,32 @@ void MainWindow::AddDocks()
//Add dock
actionDockWidgetToolOptions = ui->dockWidgetToolOptions->toggleViewAction();
ui->menuWindow->addAction(actionDockWidgetToolOptions);
connect(actionDockWidgetToolOptions, &QAction::triggered, this, [this](bool checked)
{
isDockToolOptionsVisible = checked;
m_toolOptionsActive = checked;
});
ui->menuWindow->addAction(actionDockWidgetToolOptions);
actionDockWidgetGroups = ui->dockWidgetGroups->toggleViewAction();
ui->menuWindow->addAction(actionDockWidgetGroups);
connect(actionDockWidgetGroups, &QAction::triggered, this, [this](bool checked)
{
isDockGroupsVisible = checked;
m_groupsActive = checked;
});
ui->menuWindow->addAction(actionDockWidgetGroups);
ui->menuWindow->addAction(ui->dockWidgetMessages->toggleViewAction());
QAction *action = ui->dockWidgetMessages->toggleViewAction();
connect(action, &QAction::triggered, this, [this](bool checked)
{
m_patternMessagesActive = checked;
});
ui->menuWindow->addAction(action);
actionDockWidgetBackgroundImages = ui->dockWidgetBackgroundImages->toggleViewAction();
connect(actionDockWidgetBackgroundImages, &QAction::triggered, this, [this](bool checked)
{
m_backgroundImagesActive = checked;
});
ui->menuWindow->addAction(actionDockWidgetBackgroundImages);
}
//---------------------------------------------------------------------------------------------------------------------
@ -4977,7 +5233,7 @@ void MainWindow::InitDocksContain()
qCDebug(vMainWindow, "Initialization groups dock.");
groupsWidget = new VWidgetGroups(doc, this);
ui->dockWidgetGroups->setWidget(groupsWidget);
connect(doc,&VAbstractPattern::UpdateGroups , this, &MainWindow::UpdateVisibilityGroups);
connect(doc, &VAbstractPattern::UpdateGroups, this, &MainWindow::UpdateVisibilityGroups);
detailsWidget = new VWidgetDetails(pattern, doc, this);
connect(doc, &VPattern::FullUpdateFromFile, detailsWidget, &VWidgetDetails::UpdateList);
@ -4985,6 +5241,10 @@ void MainWindow::InitDocksContain()
connect(doc, &VPattern::ShowDetail, detailsWidget, &VWidgetDetails::SelectDetail);
connect(detailsWidget, &VWidgetDetails::Highlight, sceneDetails, &VMainGraphicsScene::HighlightItem);
detailsWidget->setVisible(false);
backgroundImagesWidget = new VWidgetBackgroundImages(doc, this);
ui->dockWidgetBackgroundImages->setWidget(backgroundImagesWidget);
connect(backgroundImagesWidget, &VWidgetBackgroundImages::DeleteImage, this, &MainWindow::RemoveBackgroundImage);
}
//---------------------------------------------------------------------------------------------------------------------
@ -5316,6 +5576,8 @@ MainWindow::~MainWindow()
delete doc;
delete ui;
qDeleteAll(m_deletedBackgroundImageItems);
}
//---------------------------------------------------------------------------------------------------------------------
@ -5576,9 +5838,20 @@ bool MainWindow::LoadPattern(QString fileName, const QString& customMeasureFile)
/* Collect garbage only after successfully parse. This way wrongly accused items have one more time to restore
* a reference. */
QTimer::singleShot(100, Qt::CoarseTimer, this, [this](){doc->GarbageCollector(true);});
QTimer::singleShot(500, Qt::CoarseTimer, this, [this]()
{
QVector<VBackgroundPatternImage> allImages = doc->GetBackgroundImages();
for (const auto &image : allImages)
{
NewBackgroundImageItem(image);
}
backgroundImagesWidget->UpdateImages();
});
}
patternReadOnly = doc->IsReadOnly();
sceneDraw->SetAcceptDrop(true);
SetEnableWidgets(true);
setCurrentFile(fileName);
qCDebug(vMainWindow, "File loaded.");
@ -6562,6 +6835,7 @@ void MainWindow::ToolSelectPoint()
emit EnableElArcSelection(false);
emit EnableSplineSelection(false);
emit EnableSplinePathSelection(false);
emit EnableBackgroundImageSelection(false);
// Hovering
emit EnableLabelHover(true);
@ -6571,6 +6845,7 @@ void MainWindow::ToolSelectPoint()
emit EnableElArcHover(false);
emit EnableSplineHover(false);
emit EnableSplinePathHover(false);
emit EnableImageBackgroundHover(false);
ui->view->AllowRubberBand(false);
}
@ -6600,6 +6875,7 @@ void MainWindow::ToolSelectSpline()
emit EnableElArcSelection(false);
emit EnableSplineSelection(false);
emit EnableSplinePathSelection(false);
emit EnableBackgroundImageSelection(false);
// Hovering
emit EnableLabelHover(false);
@ -6609,6 +6885,7 @@ void MainWindow::ToolSelectSpline()
emit EnableElArcHover(false);
emit EnableSplineHover(true);
emit EnableSplinePathHover(false);
emit EnableImageBackgroundHover(false);
emit ItemsSelection(SelectionType::ByMouseRelease);
@ -6626,6 +6903,7 @@ void MainWindow::ToolSelectSplinePath()
emit EnableElArcSelection(false);
emit EnableSplineSelection(false);
emit EnableSplinePathSelection(false);
emit EnableBackgroundImageSelection(false);
// Hovering
emit EnableLabelHover(false);
@ -6635,6 +6913,7 @@ void MainWindow::ToolSelectSplinePath()
emit EnableElArcHover(false);
emit EnableSplineHover(false);
emit EnableSplinePathHover(true);
emit EnableImageBackgroundHover(false);
emit ItemsSelection(SelectionType::ByMouseRelease);
@ -6652,6 +6931,7 @@ void MainWindow::ToolSelectArc()
emit EnableElArcSelection(false);
emit EnableSplineSelection(false);
emit EnableSplinePathSelection(false);
emit EnableBackgroundImageSelection(false);
// Hovering
emit EnableLabelHover(false);
@ -6661,6 +6941,7 @@ void MainWindow::ToolSelectArc()
emit EnableElArcHover(false);
emit EnableSplineHover(false);
emit EnableSplinePathHover(false);
emit EnableImageBackgroundHover(false);
emit ItemsSelection(SelectionType::ByMouseRelease);
@ -6678,6 +6959,7 @@ void MainWindow::ToolSelectPointArc()
emit EnableElArcSelection(false);
emit EnableSplineSelection(false);
emit EnableSplinePathSelection(false);
emit EnableBackgroundImageSelection(false);
// Hovering
emit EnableLabelHover(true);
@ -6687,6 +6969,7 @@ void MainWindow::ToolSelectPointArc()
emit EnableElArcHover(false);
emit EnableSplineHover(false);
emit EnableSplinePathHover(false);
emit EnableImageBackgroundHover(false);
emit ItemsSelection(SelectionType::ByMouseRelease);
@ -6704,6 +6987,7 @@ void MainWindow::ToolSelectCurve()
emit EnableElArcSelection(false);
emit EnableSplineSelection(false);
emit EnableSplinePathSelection(false);
emit EnableBackgroundImageSelection(false);
// Hovering
emit EnableLabelHover(false);
@ -6713,6 +6997,7 @@ void MainWindow::ToolSelectCurve()
emit EnableElArcHover(true);
emit EnableSplineHover(true);
emit EnableSplinePathHover(true);
emit EnableImageBackgroundHover(false);
emit ItemsSelection(SelectionType::ByMouseRelease);
@ -6730,6 +7015,7 @@ void MainWindow::ToolSelectAllDrawObjects()
emit EnableElArcSelection(false);
emit EnableSplineSelection(false);
emit EnableSplinePathSelection(false);
emit EnableBackgroundImageSelection(false);
// Hovering
emit EnableLabelHover(true);
@ -6739,6 +7025,7 @@ void MainWindow::ToolSelectAllDrawObjects()
emit EnableElArcHover(true);
emit EnableSplineHover(true);
emit EnableSplinePathHover(true);
emit EnableImageBackgroundHover(false);
emit ItemsSelection(SelectionType::ByMouseRelease);
@ -6756,6 +7043,7 @@ void MainWindow::ToolSelectOperationObjects()
emit EnableElArcSelection(true);
emit EnableSplineSelection(true);
emit EnableSplinePathSelection(true);
emit EnableBackgroundImageSelection(false);
// Hovering
emit EnableLabelHover(true);
@ -6765,6 +7053,7 @@ void MainWindow::ToolSelectOperationObjects()
emit EnableElArcHover(true);
emit EnableSplineHover(true);
emit EnableSplinePathHover(true);
emit EnableImageBackgroundHover(false);
emit ItemsSelection(SelectionType::ByMouseRelease);

View file

@ -55,6 +55,10 @@ class VWidgetDetails;
class QToolButton;
class QProgressBar;
class WatermarkWindow;
class Quuid;
class VBackgroundImageItem;
class VBackgroundImageControls;
class VWidgetBackgroundImages;
/**
* @brief The MainWindow class main windows.
@ -74,6 +78,8 @@ public slots:
virtual void UpdateVisibilityGroups() override;
virtual void UpdateDetailsList() override;
virtual void ZoomFitBestCurrent() override;
void PlaceBackgroundImage(const QPointF &pos, const QString &fileName);
void RemoveBackgroundImage(const QUuid &id);
signals:
void RefreshHistory();
@ -90,6 +96,7 @@ signals:
void EnableNodeLabelSelection(bool enable);
void EnableNodePointSelection(bool enable);
void EnableDetailSelection(bool enable);
void EnableBackgroundImageSelection(bool enable);
void EnableLabelHover(bool enable);
void EnablePointHover(bool enable);
@ -101,6 +108,7 @@ signals:
void EnableNodeLabelHover(bool enable);
void EnableNodePointHover(bool enable);
void EnableDetailHover(bool enable);
void EnableImageBackgroundHover(bool enable);
protected:
virtual void keyPressEvent(QKeyEvent *event) override;
virtual void showEvent(QShowEvent *event) override;
@ -192,6 +200,8 @@ private slots:
void on_actionCreateManualLayout_triggered();
void on_actionUpdateManualLayout_triggered();
void ActionAddBackgroundImage();
void ClosedDialogUnionDetails(int result);
void ClosedDialogDuplicateDetail(int result);
void ClosedDialogGroup(int result);
@ -226,6 +236,11 @@ private slots:
void SetDefaultGUILanguage();
void AddBackgroundImageItem(const QUuid &id);
void DeleteBackgroundImageItem(const QUuid &id);
void ShowBackgroundImageInExplorer(const QUuid &id);
void SaveBackgroundImage(const QUuid &id);
private:
Q_DISABLE_COPY(MainWindow)
/** @brief ui keeps information about user interface */
@ -269,9 +284,6 @@ private:
/** @brief currentToolBoxIndex save current set of tools. */
qint32 currentToolBoxIndex;
bool isDockToolOptionsVisible{false};
bool isDockGroupsVisible{false};
/** @brief drawMode true if we current draw scene. */
bool drawMode;
@ -291,6 +303,7 @@ private:
VToolOptionsPropertyBrowser *toolOptions;
VWidgetGroups *groupsWidget;
VWidgetDetails *detailsWidget;
VWidgetBackgroundImages *backgroundImagesWidget{nullptr};
QSharedPointer<VLockGuard<char>> lock;
QList<QToolButton*> toolButtonPointerList;
@ -308,6 +321,15 @@ private:
QTimer *m_gradation;
QMap<QUuid, VBackgroundImageItem *> m_backgroundImages{};
QMap<QUuid, VBackgroundImageItem *> m_deletedBackgroundImageItems{};
VBackgroundImageControls *m_backgroudcontrols{nullptr};
bool m_groupsActive{false};
bool m_toolOptionsActive{false};
bool m_patternMessagesActive{false};
bool m_backgroundImagesActive{false};
void InitDimensionControls();
void InitDimensionGradation(int index, const MeasurementDimension_p &dimension, const QPointer<QComboBox> &control);
@ -422,6 +444,8 @@ private:
void StoreDimensions();
void ExportDraw(const QString &fileName);
void NewBackgroundImageItem(const VBackgroundPatternImage &image);
};
#endif // MAINWINDOW_H

View file

@ -1613,7 +1613,7 @@
<x>0</x>
<y>0</y>
<width>140</width>
<height>168</height>
<height>169</height>
</rect>
</property>
<attribute name="icon">
@ -1778,6 +1778,8 @@
<addaction name="actionLast_tool"/>
<addaction name="actionShowCurveDetails"/>
<addaction name="actionShowMainPath"/>
<addaction name="separator"/>
<addaction name="actionAddBackgroundImage"/>
</widget>
<widget class="QMenu" name="menuMeasurements">
<property name="title">
@ -2185,6 +2187,15 @@
</layout>
</widget>
</widget>
<widget class="QDockWidget" name="dockWidgetBackgroundImages">
<property name="windowTitle">
<string>Background images</string>
</property>
<attribute name="dockWidgetArea">
<number>2</number>
</attribute>
<widget class="QWidget" name="dockWidgetContents_3"/>
</widget>
<action name="actionNew">
<property name="icon">
<iconset theme="document-new">
@ -3094,6 +3105,14 @@
<string>Shop</string>
</property>
</action>
<action name="actionAddBackgroundImage">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Add background image</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>

View file

@ -107,6 +107,7 @@ protected:
QAction *redoAction{nullptr};
QAction *actionDockWidgetToolOptions{nullptr};
QAction *actionDockWidgetGroups{nullptr};
QAction *actionDockWidgetBackgroundImages{nullptr};
bool isNoScaling{false};
bool isNeedAutosave{false};

View file

@ -4408,7 +4408,7 @@ QT_WARNING_DISABLE_GCC("-Wswitch-default")
QRectF VPattern::ActiveDrawBoundingRect() const
{
// This check helps to find missed tools in the switch
Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55, "Not all tools were used.");
Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 59, "Not all tools were used.");
QRectF rec;
@ -4427,6 +4427,10 @@ QRectF VPattern::ActiveDrawBoundingRect() const
case Tool::Cut:
case Tool::Midpoint:// Same as Tool::AlongLine, but tool will never has such type
case Tool::ArcIntersectAxis:// Same as Tool::CurveIntersectAxis, but tool will never has such type
case Tool::BackgroundImage:// Not part of active draw
case Tool::BackgroundImageControls:// Not part of active draw
case Tool::BackgroundPixmapImage:// Not part of active draw
case Tool::BackgroundSVGImage:// Not part of active draw
case Tool::LAST_ONE_DO_NOT_USE:
Q_UNREACHABLE();
break;

View file

@ -59,6 +59,28 @@
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="backgroudImages" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="backgroudImage" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="imageId" type="uuid" use="required"/>
<xs:attribute name="contentType" type="contentType"/>
<xs:attribute name="path" type="xs:string"/>
<xs:attribute name="name" type="xs:string"/>
<xs:attribute name="transform" type="Transformation"/>
<xs:attribute name="hold" type="xs:boolean"/>
<xs:attribute name="visible" type="xs:boolean"/>
<xs:attribute name="zValue" type="xs:unsignedInt"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="measurements" type="xs:string"/>
<xs:element name="increments">
<xs:complexType>
@ -778,6 +800,10 @@
<xs:selector xpath="patternMaterials/material"/>
<xs:field xpath="@number"/>
</xs:unique>
<xs:unique name="imageId">
<xs:selector xpath="backgroudImages/backgroudImage"/>
<xs:field xpath="@imageId"/>
</xs:unique>
</xs:element>
<xs:simpleType name="shortName">
<xs:restriction base="xs:string">
@ -1129,4 +1155,9 @@
<xs:attribute name="alignment" type="alignmentType"/>
<xs:attribute name="sfIncrement" type="xs:unsignedInt"/>
</xs:complexType>
<xs:simpleType name="Transformation">
<xs:restriction base="xs:string">
<xs:pattern value="([-+]?\d+\.?\d*([eE][-+]?\d+)?;){8,}[-+]?\d+\.?\d*([eE][-+]?\d+)?"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>

110
src/libs/ifc/xml/utils.cpp Normal file
View file

@ -0,0 +1,110 @@
/************************************************************************
**
** @file utils.cpp
** @author Roman Telezhynskyi <dismine(at)gmail.com>
** @date 12 1, 2022
**
** @brief
** @copyright
** This source code is part of the Valentina project, a pattern making
** program, whose allow create and modeling patterns of clothing.
** Copyright (C) 2022 Valentina project
** <https://gitlab.com/smart-pattern/valentina> All Rights Reserved.
**
** Valentina is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Valentina 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
**
*************************************************************************/
#include "utils.h"
#include <QImageReader>
#include <QMimeDatabase>
#include <QMimeType>
#include <QRegularExpressionMatch>
#include <QSet>
#include <QStringList>
#include <QSvgRenderer>
//---------------------------------------------------------------------------------------------------------------------
auto IsMimeTypeImage(const QMimeType &mime) -> bool
{
QStringList aliases = mime.aliases();
aliases.prepend(mime.name());
QRegularExpression rx(QStringLiteral("^image\\/[-\\w]+(\\.[-\\w]+)*([+][-\\w]+)?$"));
return std::any_of(aliases.begin(), aliases.end(), [rx](const QString &name) { return rx.match(name).hasMatch(); });
}
//---------------------------------------------------------------------------------------------------------------------
auto SplitString(QString str) -> QStringList
{
QStringList list;
const int n = 80;
while (not str.isEmpty())
{
list.append(str.left(n));
str.remove(0, n);
}
return list;
}
//---------------------------------------------------------------------------------------------------------------------
auto MimeTypeFromByteArray(const QByteArray &data) -> QMimeType
{
QMimeType mime = QMimeDatabase().mimeTypeForData(data);
QSet<QString> aliases = mime.aliases().toSet();
aliases.insert(mime.name());
QSet<QString> gzipMime {"application/gzip", "application/x-gzip"};
if (gzipMime.contains(aliases))
{
QSvgRenderer render(data);
if (render.isValid())
{
mime = QMimeDatabase().mimeTypeForName(QStringLiteral("image/svg+xml-compressed"));
}
}
return mime;
}
//---------------------------------------------------------------------------------------------------------------------
auto PrepareImageFilters() -> QString
{
const QList<QByteArray> supportedFormats = QImageReader::supportedImageFormats();
const QSet<QString> filterFormats{"bmp", "jpeg", "jpg", "png", "svg", "svgz", "tif", "tiff", "webp"};
QStringList sufixes;
for (const auto& format : supportedFormats)
{
if (filterFormats.contains(format))
{
sufixes.append(QStringLiteral("*.%1").arg(QString(format)));
}
}
QStringList filters;
if (not sufixes.isEmpty())
{
filters.append(QObject::tr("Images") + QStringLiteral(" (%1)").arg(sufixes.join(' ')));
}
filters.append(QObject::tr("All files") + QStringLiteral(" (*.*)"));
return filters.join(QStringLiteral(";;"));
}

42
src/libs/ifc/xml/utils.h Normal file
View file

@ -0,0 +1,42 @@
/************************************************************************
**
** @file utils.h
** @author Roman Telezhynskyi <dismine(at)gmail.com>
** @date 12 1, 2022
**
** @brief
** @copyright
** This source code is part of the Valentina project, a pattern making
** program, whose allow create and modeling patterns of clothing.
** Copyright (C) 2022 Valentina project
** <https://gitlab.com/smart-pattern/valentina> All Rights Reserved.
**
** Valentina is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Valentina 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
**
*************************************************************************/
#ifndef UTILS_H
#define UTILS_H
class QMimeType;
class QString;
class QStringList;
class QMimeType;
class QByteArray;
auto IsMimeTypeImage(const QMimeType &mime) -> bool;
auto SplitString(QString str) -> QStringList;
auto MimeTypeFromByteArray(const QByteArray &data) -> QMimeType;
auto PrepareImageFilters() -> QString;
#endif // UTILS_H

View file

@ -59,6 +59,7 @@
#include "../vmisc/compatibility.h"
#include "../vlayout/vtextmanager.h"
#include "vpatternimage.h"
#include "vbackgroundpatternimage.h"
class QDomElement;
@ -102,6 +103,8 @@ const QString VAbstractPattern::TagGrainline = QStringLiteral("grainline"
const QString VAbstractPattern::TagPath = QStringLiteral("path");
const QString VAbstractPattern::TagNodes = QStringLiteral("nodes");
const QString VAbstractPattern::TagNode = QStringLiteral("node");
const QString VAbstractPattern::TagBackgroundImages = QStringLiteral("backgroudImages");
const QString VAbstractPattern::TagBackgroundImage = QStringLiteral("backgroudImage");
const QString VAbstractPattern::AttrName = QStringLiteral("name");
const QString VAbstractPattern::AttrVisible = QStringLiteral("visible");
@ -138,6 +141,10 @@ const QString VAbstractPattern::AttrManualPassmarkLength = QStringLiteral("manua
const QString VAbstractPattern::AttrPassmarkLength = QStringLiteral("passmarkLength");
const QString VAbstractPattern::AttrOpacity = QStringLiteral("opacity");
const QString VAbstractPattern::AttrTags = QStringLiteral("tags");
const QString VAbstractPattern::AttrTransform = QStringLiteral("transform");
const QString VAbstractPattern::AttrHold = QStringLiteral("hold");
const QString VAbstractPattern::AttrZValue = QStringLiteral("zValue");
const QString VAbstractPattern::AttrImageId = QStringLiteral("imageId");
const QString VAbstractPattern::AttrContentType = QStringLiteral("contentType");
@ -235,8 +242,55 @@ QString PrepareGroupTags(QStringList tags)
return ConvertToList(ConvertToSet<QString>(tags)).join(',');
}
//---------------------------------------------------------------------------------------------------------------------
auto StringToTransfrom(const QString &matrix) -> QTransform
{
QStringList elements = matrix.split(QChar(';'));
if (elements.count() == 9)
{
qreal m11 = elements.at(0).toDouble();
qreal m12 = elements.at(1).toDouble();
qreal m13 = elements.at(2).toDouble();
qreal m21 = elements.at(3).toDouble();
qreal m22 = elements.at(4).toDouble();
qreal m23 = elements.at(5).toDouble();
qreal m31 = elements.at(6).toDouble();
qreal m32 = elements.at(7).toDouble();
qreal m33 = elements.at(8).toDouble();
return {m11, m12, m13, m21, m22, m23, m31, m32, m33};
}
return {};
}
//---------------------------------------------------------------------------------------------------------------------
template <class T>
auto NumberToString(T number) -> QString
{
const QLocale locale = QLocale::c();
return locale.toString(number, 'g', 12).remove(locale.groupSeparator());
}
//---------------------------------------------------------------------------------------------------------------------
auto TransformToString(const QTransform &m) -> QString
{
QStringList matrix
{
NumberToString(m.m11()),
NumberToString(m.m12()),
NumberToString(m.m13()),
NumberToString(m.m21()),
NumberToString(m.m22()),
NumberToString(m.m23()),
NumberToString(m.m31()),
NumberToString(m.m32()),
NumberToString(m.m33())
};
return matrix.join(QChar(';'));
}
} // namespace
//---------------------------------------------------------------------------------------------------------------------
VAbstractPattern::VAbstractPattern(QObject *parent)
: VDomDocument(parent),
@ -848,7 +902,7 @@ void VAbstractPattern::SetMPath(const QString &path)
quint32 VAbstractPattern::SiblingNodeId(const quint32 &nodeId) const
{
// This check helps to find missed tools in the switch
Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55, "Check if need to ignore modeling tools.");
Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 59, "Check if need to ignore modeling tools.");
quint32 siblingId = NULL_ID;
@ -882,6 +936,10 @@ quint32 VAbstractPattern::SiblingNodeId(const quint32 &nodeId) const
case Tool::PiecePath:
case Tool::InsertNode:
case Tool::DuplicateDetail:
case Tool::BackgroundImage:
case Tool::BackgroundImageControls:
case Tool::BackgroundPixmapImage:
case Tool::BackgroundSVGImage:
continue;
default:
siblingId = tool.getId();
@ -1267,6 +1325,126 @@ void VAbstractPattern::DeleteImage()
emit patternChanged(false);
}
//---------------------------------------------------------------------------------------------------------------------
auto VAbstractPattern::GetBackgroundImages() const -> QVector<VBackgroundPatternImage>
{
QVector<VBackgroundPatternImage> images;
const QDomNodeList list = elementsByTagName(TagBackgroundImages);
if (list.isEmpty())
{
return images;
}
QDomElement imagesTag = list.at(0).toElement();
if (not imagesTag.isNull())
{
QDomNode imageNode = imagesTag.firstChild();
while (not imageNode.isNull())
{
const QDomElement imageElement = imageNode.toElement();
if (not imageElement.isNull())
{
images.append(GetBackgroundPatternImage(imageElement));
}
imageNode = imageNode.nextSibling();
}
}
return images;
}
//---------------------------------------------------------------------------------------------------------------------
void VAbstractPattern::SaveBackgroundImages(const QVector<VBackgroundPatternImage> &images)
{
QDomElement imagesElement = CheckTagExists(TagBackgroundImages);
RemoveAllChildren(imagesElement);
for (const auto& image : images)
{
if (not image.Id().isNull())
{
QDomElement imageElement = createElement(TagBackgroundImage);
WriteBackgroundImage(imageElement, image);
imagesElement.appendChild(imageElement);
}
}
}
//---------------------------------------------------------------------------------------------------------------------
auto VAbstractPattern::GetBackgroundImage(const QUuid &id) const -> VBackgroundPatternImage
{
const QDomElement imageElement = GetBackgroundImageElement(id);
if (not imageElement.isNull())
{
return GetBackgroundPatternImage(imageElement);
}
return {};
}
//---------------------------------------------------------------------------------------------------------------------
void VAbstractPattern::SaveBackgroundImage(const VBackgroundPatternImage &image)
{
QDomElement imageElement = GetBackgroundImageElement(image.Id());
if (imageElement.isNull())
{
QDomElement imageElement = createElement(TagBackgroundImage);
WriteBackgroundImage(imageElement, image);
QDomElement imagesElement = CheckTagExists(TagBackgroundImages);
imagesElement.appendChild(imageElement);
}
else
{
WriteBackgroundImage(imageElement, image);
}
modified = true;
emit patternChanged(false);
}
//---------------------------------------------------------------------------------------------------------------------
void VAbstractPattern::DeleteBackgroundImage(const QUuid &id)
{
const QDomNodeList list = elementsByTagName(TagBackgroundImages);
if (list.isEmpty())
{
return;
}
QDomElement imagesTag = list.at(0).toElement();
if (not imagesTag.isNull())
{
QDomNode imageNode = imagesTag.firstChild();
while (not imageNode.isNull())
{
const QDomElement imageElement = imageNode.toElement();
if (not imageElement.isNull())
{
QUuid imageId = QUuid(GetParametrEmptyString(imageElement, AttrImageId));
if (imageId == id)
{
imagesTag.removeChild(imageElement);
if (imagesTag.childNodes().size() == 0)
{
QDomNode parent = imagesTag.parentNode();
if (not parent.isNull())
{
parent.removeChild(imagesTag);
}
}
modified = true;
emit patternChanged(false);
return;
}
}
imageNode = imageNode.nextSibling();
}
}
}
//---------------------------------------------------------------------------------------------------------------------
QString VAbstractPattern::GetVersion() const
{
@ -1357,7 +1535,7 @@ void VAbstractPattern::SetActivPP(const QString &name)
}
//---------------------------------------------------------------------------------------------------------------------
QDomElement VAbstractPattern::CheckTagExists(const QString &tag)
auto VAbstractPattern::CheckTagExists(const QString &tag) -> QDomElement
{
const QDomNodeList list = elementsByTagName(tag);
QDomElement element;
@ -1378,7 +1556,8 @@ QDomElement VAbstractPattern::CheckTagExists(const QString &tag)
TagPatternLabel, // 10
TagWatermark, // 11
TagPatternMaterials, // 12
TagFinalMeasurements // 13
TagFinalMeasurements, // 13
TagBackgroundImages // 14
};
switch (tags.indexOf(tag))
@ -1422,9 +1601,12 @@ QDomElement VAbstractPattern::CheckTagExists(const QString &tag)
case 13: // TagFinalMeasurements
element = createElement(TagFinalMeasurements);
break;
case 14: // TagBackgroundImages
element = createElement(TagBackgroundImages);
break;
case 0: //TagUnit (Mandatory tag)
default:
return QDomElement();
return {};
}
InsertTag(tags, element);
return element;
@ -1531,7 +1713,7 @@ QVector<VFormulaField> VAbstractPattern::ListPointExpressions() const
// Check if new tool doesn't bring new attribute with a formula.
// If no just increment a number.
// If new tool bring absolutely new type and has formula(s) create new method to cover it.
Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55);
Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 59);
QVector<VFormulaField> expressions;
const QDomNodeList list = elementsByTagName(TagPoint);
@ -1559,7 +1741,7 @@ QVector<VFormulaField> VAbstractPattern::ListArcExpressions() const
// Check if new tool doesn't bring new attribute with a formula.
// If no just increment number.
// If new tool bring absolutely new type and has formula(s) create new method to cover it.
Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55);
Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 59);
QVector<VFormulaField> expressions;
const QDomNodeList list = elementsByTagName(TagArc);
@ -1583,7 +1765,7 @@ QVector<VFormulaField> VAbstractPattern::ListElArcExpressions() const
// Check if new tool doesn't bring new attribute with a formula.
// If no just increment number.
// If new tool bring absolutely new type and has formula(s) create new method to cover it.
Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55);
Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 59);
QVector<VFormulaField> expressions;
const QDomNodeList list = elementsByTagName(TagElArc);
@ -1616,7 +1798,7 @@ QVector<VFormulaField> VAbstractPattern::ListPathPointExpressions() const
// Check if new tool doesn't bring new attribute with a formula.
// If no just increment number.
// If new tool bring absolutely new type and has formula(s) create new method to cover it.
Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55);
Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 59);
QVector<VFormulaField> expressions;
const QDomNodeList list = elementsByTagName(AttrPathPoint);
@ -1654,7 +1836,7 @@ QVector<VFormulaField> VAbstractPattern::ListOperationExpressions() const
// Check if new tool doesn't bring new attribute with a formula.
// If no just increment number.
// If new tool bring absolutely new type and has formula(s) create new method to cover it.
Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55);
Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 59);
QVector<VFormulaField> expressions;
const QDomNodeList list = elementsByTagName(TagOperation);
@ -1676,7 +1858,7 @@ QVector<VFormulaField> VAbstractPattern::ListNodesExpressions(const QDomElement
// Check if new tool doesn't bring new attribute with a formula.
// If no just increment number.
// If new tool bring absolutely new type and has formula(s) create new method to cover it.
Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55);
Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 59);
QVector<VFormulaField> expressions;
@ -1700,7 +1882,7 @@ QVector<VFormulaField> VAbstractPattern::ListPathExpressions() const
// Check if new tool doesn't bring new attribute with a formula.
// If no just increment number.
// If new tool bring absolutely new type and has formula(s) create new method to cover it.
Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55);
Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 59);
QVector<VFormulaField> expressions;
const QDomNodeList list = elementsByTagName(TagPath);
@ -1738,7 +1920,7 @@ QVector<VFormulaField> VAbstractPattern::ListPieceExpressions() const
// Check if new tool doesn't bring new attribute with a formula.
// If no just increment number.
// If new tool bring absolutely new type and has formula(s) create new method to cover it.
Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55);
Q_STATIC_ASSERT(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 59);
QVector<VFormulaField> expressions;
const QDomNodeList list = elementsByTagName(TagDetail);
@ -1951,6 +2133,96 @@ void VAbstractPattern::SetFMeasurements(QDomElement &element, const QVector<VFin
}
}
//---------------------------------------------------------------------------------------------------------------------
auto VAbstractPattern::GetBackgroundPatternImage(const QDomElement &element) const -> VBackgroundPatternImage
{
VBackgroundPatternImage image;
image.SetId(QUuid(GetParametrEmptyString(element, AttrImageId)));
QString path = GetParametrEmptyString(element, AttrPath);
if (not path.isEmpty())
{
image.SetFilePath(path);
}
else
{
QString contentType = GetParametrEmptyString(element, AttrContentType);
QByteArray contentData = element.text().toLatin1();
image.SetContentData(contentData, contentType);
}
image.SetName(GetParametrEmptyString(element, AttrName));
image.SetHold(GetParametrBool(element, AttrHold, falseStr));
image.SetZValue(GetParametrUInt(element, AttrZValue, QChar('0')));
image.SetVisible(GetParametrBool(element, AttrVisible, trueStr));
QString matrix = GetParametrEmptyString(element, AttrTransform);
image.SetMatrix(StringToTransfrom(matrix));
return image;
}
//---------------------------------------------------------------------------------------------------------------------
auto VAbstractPattern::GetBackgroundImageElement(const QUuid &id) const -> QDomElement
{
const QDomNodeList list = elementsByTagName(TagBackgroundImages);
if (not list.isEmpty())
{
QDomElement imagesTag = list.at(0).toElement();
if (not imagesTag.isNull())
{
QDomNode imageNode = imagesTag.firstChild();
while (not imageNode.isNull())
{
if (imageNode.isElement())
{
const QDomElement imageElement = imageNode.toElement();
if (not imageElement.isNull())
{
QUuid imageId = QUuid(GetParametrEmptyString(imageElement, AttrImageId));
if (imageId == id)
{
return imageElement;
}
}
}
imageNode = imageNode.nextSibling();
}
}
}
return {};
}
//---------------------------------------------------------------------------------------------------------------------
void VAbstractPattern::WriteBackgroundImage(QDomElement &element, const VBackgroundPatternImage &image)
{
SetAttribute(element, AttrImageId, image.Id().toString());
if (not image.FilePath().isEmpty())
{
SetAttribute(element, AttrPath, image.FilePath());
element.removeAttribute(AttrContentType);
setTagText(element, QString());
}
else
{
SetAttributeOrRemoveIf<QString>(element, AttrContentType, image.ContentType(),
[](const QString &contentType) noexcept {return contentType.isEmpty();});
setTagText(element, image.ContentData());
SetAttributeOrRemoveIf<QString>(element, AttrPath, image.FilePath(),
[](const QString &path) noexcept {return path.isEmpty();});
}
SetAttributeOrRemoveIf<QString>(element, AttrName, image.Name(),
[](const QString &name) noexcept {return name.isEmpty();});
SetAttribute(element, AttrTransform, TransformToString(image.Matrix()));
SetAttributeOrRemoveIf<bool>(element, AttrHold, image.Hold(), [](bool hold) noexcept {return not hold;});
SetAttributeOrRemoveIf<qreal>(element, AttrZValue, image.ZValue(), [](qreal z) noexcept {return qFuzzyIsNull(z);});
SetAttributeOrRemoveIf<bool>(element, AttrVisible, image.Visible(), [](bool visible) noexcept {return visible;});
}
//---------------------------------------------------------------------------------------------------------------------
/**
* @brief IsModified state of the document for cases that do not cover QUndoStack.

View file

@ -39,6 +39,7 @@
#include <QStringList>
#include <QVector>
#include <QtGlobal>
#include <QUuid>
#include "../vmisc/def.h"
#include "vdomdocument.h"
@ -49,6 +50,7 @@ class QDomElement;
class VPiecePath;
class VPieceNode;
class VPatternImage;
class VBackgroundPatternImage;
enum class Document : qint8 { FullLiteParse, LiteParse, LitePPParse, FullParse };
enum class LabelType : qint8 {NewPatternPiece, NewLabel};
@ -205,6 +207,12 @@ public:
bool SetImage(const VPatternImage &image);
void DeleteImage();
auto GetBackgroundImages() const -> QVector<VBackgroundPatternImage>;
void SaveBackgroundImages(const QVector<VBackgroundPatternImage> &images);
auto GetBackgroundImage(const QUuid &id) const -> VBackgroundPatternImage;
void SaveBackgroundImage(const VBackgroundPatternImage &image);
void DeleteBackgroundImage(const QUuid &id);
QString GetVersion() const;
void SetVersion();
@ -282,6 +290,8 @@ public:
static const QString TagPath;
static const QString TagNodes;
static const QString TagNode;
static const QString TagBackgroundImages;
static const QString TagBackgroundImage;
static const QString AttrName;
static const QString AttrVisible;
@ -318,6 +328,10 @@ public:
static const QString AttrPassmarkLength;
static const QString AttrOpacity;
static const QString AttrTags;
static const QString AttrTransform;
static const QString AttrHold;
static const QString AttrZValue;
static const QString AttrImageId;
static const QString AttrContentType;
@ -378,6 +392,15 @@ signals:
void UpdateGroups();
void UpdateToolTip();
void BackgroundImageTransformationChanged(QUuid id);
void BackgroundImagesHoldChanged();
void BackgroundImageHoldChanged(const QUuid &id);
void BackgroundImageVisibilityChanged(const QUuid &id);
void BackgroundImagesVisibilityChanged();
void BackgroundImageNameChanged(const QUuid &id);
void BackgroundImagesZValueChanged();
void BackgroundImagePositionChanged(const QUuid &id);
public slots:
virtual void LiteParseTree(const Document &parse)=0;
void haveLiteChange();
@ -473,6 +496,10 @@ private:
QVector<VFinalMeasurement> GetFMeasurements(const QDomElement &element) const;
void SetFMeasurements(QDomElement &element, const QVector<VFinalMeasurement> &measurements);
auto GetBackgroundPatternImage(const QDomElement &element) const -> VBackgroundPatternImage;
auto GetBackgroundImageElement(const QUuid &id) const -> QDomElement;
void WriteBackgroundImage(QDomElement &element, const VBackgroundPatternImage &image);
};
QT_WARNING_POP

View file

@ -0,0 +1,310 @@
/************************************************************************
**
** @file vbackgroundpatternimage.cpp
** @author Roman Telezhynskyi <dismine(at)gmail.com>
** @date 11 1, 2022
**
** @brief
** @copyright
** This source code is part of the Valentina project, a pattern making
** program, whose allow create and modeling patterns of clothing.
** Copyright (C) 2022 Valentina project
** <https://gitlab.com/smart-pattern/valentina> All Rights Reserved.
**
** Valentina is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Valentina 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
**
*************************************************************************/
#include "vbackgroundpatternimage.h"
#include "utils.h"
#include <QMimeType>
#include <QDebug>
#include <QFile>
#include <QMimeDatabase>
#include <QPixmap>
#include <QBuffer>
#include <QImageReader>
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundPatternImage::FromFile(const QString &fileName, bool builtIn) -> VBackgroundPatternImage
{
VBackgroundPatternImage image;
QMimeType mime = QMimeDatabase().mimeTypeForFile(fileName);
if (not IsMimeTypeImage(mime))
{
qCritical() << tr("Unexpected mime type: %1").arg(mime.name());
return {};
}
if (builtIn)
{
QFile file(fileName);
if (not file.open(QIODevice::ReadOnly))
{
qCritical() << tr("Couldn't read the image. Error: %1").arg(file.errorString());
return {};
}
QString base64 = SplitString(QString::fromLatin1(file.readAll().toBase64().data())).join('\n');
image.SetContentData(base64.toLatin1(), mime.name());
}
else
{
image.SetFilePath(fileName);
}
return image;
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundPatternImage::ContentType() const -> const QString &
{
return m_contentType;
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundPatternImage::ContentData() const -> const QByteArray &
{
return m_contentData;
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundPatternImage::SetContentData(const QByteArray &newContentData, const QString &newContentType)
{
m_contentData = newContentData;
m_contentType = newContentType;
m_filePath.clear();
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundPatternImage::IsNull() const -> bool
{
return m_filePath.isEmpty() && m_contentData.isEmpty();
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundPatternImage::IsValid() const -> bool
{
m_errorString.clear();
if (IsNull())
{
m_errorString = tr("No data.");
return false;
}
if (m_id.isNull())
{
m_errorString = tr("Invalid id.");
return false;
}
if (not m_filePath.isEmpty())
{
QMimeType mime = MimeTypeFromData();
if (not IsMimeTypeImage(mime))
{
qCritical() << tr("Unexpected mime type: %1").arg(mime.name());
return false;
}
}
else
{
if (m_contentType.isEmpty())
{
m_errorString = tr("Content type is empty.");
return false;
}
QMimeType mime = MimeTypeFromData();
QSet<QString> aliases = mime.aliases().toSet();
aliases.insert(mime.name());
if (not aliases.contains(m_contentType))
{
m_errorString = tr("Content type mistmatch.");
return false;
}
if (not IsMimeTypeImage(mime))
{
m_errorString = tr("Not image.");
return false;
}
}
return true;
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundPatternImage::MimeTypeFromData() const -> QMimeType
{
if (not m_filePath.isEmpty())
{
return QMimeDatabase().mimeTypeForFile(m_filePath);
}
if (not m_contentData.isEmpty())
{
return MimeTypeFromByteArray(QByteArray::fromBase64(m_contentData));
}
return {};
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundPatternImage::FilePath() const -> const QString &
{
return m_filePath;
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundPatternImage::SetFilePath(const QString &newFilePath)
{
m_filePath = newFilePath;
m_contentData.clear();
m_contentType.clear();
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundPatternImage::Name() const -> const QString &
{
return m_name;
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundPatternImage::SetName(const QString &newName)
{
m_name = newName;
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundPatternImage::ZValue() const -> qreal
{
return m_zValue;
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundPatternImage::SetZValue(qreal newZValue)
{
m_zValue = newZValue;
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundPatternImage::Hold() const -> bool
{
return m_hold;
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundPatternImage::SetHold(bool newHold)
{
m_hold = newHold;
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundPatternImage::Id() const -> QUuid
{
return m_id;
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundPatternImage::SetId(const QUuid &newId)
{
m_id = newId;
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundPatternImage::Size() const -> QSize
{
if (not IsValid())
{
return {};
}
if (not m_filePath.isEmpty())
{
return QImageReader(m_filePath).size();
}
if (not m_contentData.isEmpty())
{
QByteArray array = QByteArray::fromBase64(m_contentData);
QBuffer buffer(&array);
buffer.open(QIODevice::ReadOnly);
return QImageReader(&buffer).size();
}
return {};
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundPatternImage::ErrorString() const -> const QString &
{
return m_errorString;
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundPatternImage::Matrix() const -> const QTransform &
{
return m_matrix;
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundPatternImage::SetMatrix(const QTransform &newMatrix)
{
m_matrix = newMatrix;
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundPatternImage::Type() const -> PatternImage
{
if (not IsValid())
{
return PatternImage::Unknown;
}
QMimeType mime = MimeTypeFromData();
if (mime.name().startsWith(u"image/svg+xml"))
{
return PatternImage::Vector;
}
return PatternImage::Raster;
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundPatternImage::BoundingRect() const -> QRectF
{
QSize imageSize = Size();
QRectF imageRect({0, 0}, QSizeF(imageSize.width(), imageSize.height()));
return m_matrix.mapRect(imageRect);
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundPatternImage::Visible() const -> bool
{
return m_visible;
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundPatternImage::SetVisible(bool newVisible)
{
m_visible = newVisible;
}

View file

@ -0,0 +1,109 @@
/************************************************************************
**
** @file vbackgroundpatternimage.h
** @author Roman Telezhynskyi <dismine(at)gmail.com>
** @date 11 1, 2022
**
** @brief
** @copyright
** This source code is part of the Valentina project, a pattern making
** program, whose allow create and modeling patterns of clothing.
** Copyright (C) 2022 Valentina project
** <https://gitlab.com/smart-pattern/valentina> All Rights Reserved.
**
** Valentina is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Valentina 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
**
*************************************************************************/
#ifndef VBACKGROUNDPATTERNIMAGE_H
#define VBACKGROUNDPATTERNIMAGE_H
#include <QPoint>
#include <QCoreApplication>
#include <QUuid>
#include <QTransform>
#include "../vmisc/typedef.h"
class QPixmap;
class QMimeType;
enum class PatternImage
{
Raster,
Vector,
Unknown
};
class VBackgroundPatternImage
{
Q_DECLARE_TR_FUNCTIONS(VBackgroundPatternImage)
public:
VBackgroundPatternImage() = default;
static auto FromFile(const QString &fileName, bool builtIn) -> VBackgroundPatternImage;
auto ContentType() const -> const QString &;
auto ContentData() const -> const QByteArray &;
void SetContentData(const QByteArray &newContentData, const QString & newContentType);
auto IsNull() const -> bool;
auto IsValid() const -> bool;
auto MimeTypeFromData() const -> QMimeType;
auto FilePath() const -> const QString &;
void SetFilePath(const QString &newFilePath);
auto Name() const -> const QString &;
void SetName(const QString &newName);
auto ZValue() const -> qreal;
void SetZValue(qreal newZValue);
auto Hold() const -> bool;
void SetHold(bool newHold);
auto Id() const -> QUuid;
void SetId(const QUuid &newId);
auto Size() const -> QSize;
void SetSize(const QSize &newSize);
auto ErrorString() const -> const QString &;
auto Matrix() const -> const QTransform &;
void SetMatrix(const QTransform &newMatrix);
auto Type() const -> PatternImage;
auto BoundingRect() const -> QRectF;
auto Visible() const -> bool;
void SetVisible(bool newVisible);
private:
QUuid m_id{QUuid::createUuid()};
QString m_contentType{};
QByteArray m_contentData{};
mutable QString m_errorString{};
QString m_filePath{};
QString m_name{};
qreal m_zValue{0};
QTransform m_matrix{};
bool m_hold{false};
bool m_visible{true};
};
#endif // VBACKGROUNDPATTERNIMAGE_H

View file

@ -39,34 +39,7 @@
#include <QSize>
#include <QFile>
namespace
{
//---------------------------------------------------------------------------------------------------------------------
auto IsMimeTypeImage(const QMimeType &mime) -> bool
{
QStringList aliases = mime.aliases();
aliases.prepend(mime.name());
QRegularExpression rx(QStringLiteral("^image\\/[-\\w]+(\\.[-\\w]+)*([+][-\\w]+)?$"));
return std::any_of(aliases.begin(), aliases.end(), [rx](const QString &name) { return rx.match(name).hasMatch(); });
}
//---------------------------------------------------------------------------------------------------------------------
auto SplitString(QString str) -> QStringList
{
QStringList list;
const int n = 80;
while (not str.isEmpty())
{
list.append(str.left(n));
str.remove(0, n);
}
return list;
}
} // namespace
#include "utils.h"
//---------------------------------------------------------------------------------------------------------------------
@ -140,19 +113,6 @@ auto VPatternImage::IsValid() const -> bool
QSet<QString> aliases = mime.aliases().toSet();
aliases.insert(mime.name());
QSet<QString> gzipMime {"application/gzip", "application/x-gzip"};
if (gzipMime.contains(aliases))
{
QSvgRenderer render(QByteArray::fromBase64(m_contentData));
if (render.isValid())
{
mime = QMimeDatabase().mimeTypeForName(QStringLiteral("image/svg+xml-compressed"));
aliases = mime.aliases().toSet();
aliases.insert(mime.name());
}
}
if (not aliases.contains(m_contentType))
{
m_errorString = tr("Content type mistmatch.");
@ -202,7 +162,7 @@ auto VPatternImage::ErrorString() const -> const QString &
//---------------------------------------------------------------------------------------------------------------------
auto VPatternImage::MimeTypeFromData() const -> QMimeType
{
return QMimeDatabase().mimeTypeForData(QByteArray::fromBase64(m_contentData));
return MimeTypeFromByteArray(QByteArray::fromBase64(m_contentData));
}
//---------------------------------------------------------------------------------------------------------------------

View file

@ -31,7 +31,6 @@
#include <QString>
#include <QCoreApplication>
class QPixmap;
class QMimeType;

View file

@ -2,7 +2,9 @@
# This need for corect working file translations.pro
HEADERS += \
$$PWD/utils.h \
$$PWD/vabstractconverter.h \
$$PWD/vbackgroundpatternimage.h \
$$PWD/vdomdocument.h \
$$PWD/vlayoutconverter.h \
$$PWD/vpatternconverter.h \
@ -16,7 +18,9 @@ HEADERS += \
$$PWD/vwatermarkconverter.h
SOURCES += \
$$PWD/utils.cpp \
$$PWD/vabstractconverter.cpp \
$$PWD/vbackgroundpatternimage.cpp \
$$PWD/vdomdocument.cpp \
$$PWD/vlayoutconverter.cpp \
$$PWD/vpatternconverter.cpp \

View file

@ -299,7 +299,7 @@ QDomElement VPatternRecipe::Draft(const QDomElement &draft)
QDomElement VPatternRecipe::Step(const VToolRecord &tool, const VContainer &data)
{
// This check helps to find missed tools in the switch
Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 55, "Not all tools were used in history.");
Q_STATIC_ASSERT_X(static_cast<int>(Tool::LAST_ONE_DO_NOT_USE) == 59, "Not all tools were used in history.");
const QDomElement domElem = m_pattern->elementById(tool.getId());
if (not domElem.isElement() && tool.IsMandatory())
@ -320,6 +320,10 @@ QT_WARNING_DISABLE_GCC("-Wswitch-default")
case Tool::Cut:
case Tool::Midpoint:// Same as Tool::AlongLine, but tool will never has such type
case Tool::ArcIntersectAxis:// Same as Tool::CurveIntersectAxis, but tool will never has such type
case Tool::BackgroundImage:
case Tool::BackgroundImageControls:
case Tool::BackgroundPixmapImage:
case Tool::BackgroundSVGImage:
case Tool::LAST_ONE_DO_NOT_USE:
Q_UNREACHABLE(); //-V501
break;

View file

@ -205,6 +205,10 @@ enum class Tool : ToolVisHolderType
InsertNode,
PlaceLabel,
DuplicateDetail,
BackgroundImage,
BackgroundImageControls,
BackgroundPixmapImage,
BackgroundSVGImage,
LAST_ONE_DO_NOT_USE //add new stuffs above this, this constant must be last and never used
};

View file

@ -48,4 +48,13 @@ void qAsConst(const T &&) Q_DECL_EQ_DELETE;
Class &operator=(const Class &) Q_DECL_EQ_DELETE;
#endif
#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
#define Q_DISABLE_MOVE(Class) \
Class(Class &&) = delete; \
Class &operator=(Class &&) = delete;
#define Q_DISABLE_COPY_MOVE(Class) \
Q_DISABLE_COPY(Class) \
Q_DISABLE_MOVE(Class)
#endif
#endif // DEFGLOBAL_H

View file

@ -94,5 +94,58 @@
<file>icon/24x24/close.png</file>
<file>icon/24x24/close@2x.png</file>
<file>icon/layout.png</file>
<file>icon/32x32/rotate-top-left-hover@2x.png</file>
<file>icon/32x32/rotate-top-left-hover.png</file>
<file>icon/32x32/rotate-top-left@2x.png</file>
<file>icon/32x32/rotate-top-left.png</file>
<file>icon/32x32/rotate-top-right-hover@2x.png</file>
<file>icon/32x32/rotate-top-right-hover.png</file>
<file>icon/32x32/rotate-top-right@2x.png</file>
<file>icon/32x32/rotate-top-right.png</file>
<file>icon/32x32/rotate-bottom-right-hover@2x.png</file>
<file>icon/32x32/rotate-bottom-right-hover.png</file>
<file>icon/32x32/rotate-bottom-right@2x.png</file>
<file>icon/32x32/rotate-bottom-right.png</file>
<file>icon/32x32/rotate-bottom-left-hover@2x.png</file>
<file>icon/32x32/rotate-bottom-left-hover.png</file>
<file>icon/32x32/rotate-bottom-left@2x.png</file>
<file>icon/32x32/rotate-bottom-left.png</file>
<file>icon/32x32/expand2-hover@2x.png</file>
<file>icon/32x32/expand2-hover.png</file>
<file>icon/32x32/expand2@2x.png</file>
<file>icon/32x32/expand2.png</file>
<file>icon/32x32/expand1-hover@2x.png</file>
<file>icon/32x32/expand1-hover.png</file>
<file>icon/32x32/expand1@2x.png</file>
<file>icon/32x32/expand1.png</file>
<file>icon/32x32/double-arrow-vertical-hover@2x.png</file>
<file>icon/32x32/double-arrow-vertical-hover.png</file>
<file>icon/32x32/double-arrow-vertical@2x.png</file>
<file>icon/32x32/double-arrow-vertical.png</file>
<file>icon/32x32/double-arrow-horizontal-hover@2x.png</file>
<file>icon/32x32/double-arrow-horizontal@2x.png</file>
<file>icon/32x32/double-arrow-horizontal-hover.png</file>
<file>icon/32x32/double-arrow-horizontal.png</file>
<file>icon/svg/broken_path.svg</file>
<file>icon/16x16/not_hold_image@2x.png</file>
<file>icon/16x16/not_hold_image.png</file>
<file>icon/16x16/hold_image@2x.png</file>
<file>icon/16x16/hold_image.png</file>
<file>icon/32x32/rotate-top-right-disabled@2x.png</file>
<file>icon/32x32/rotate-top-right-disabled.png</file>
<file>icon/32x32/rotate-top-left-disabled@2x.png</file>
<file>icon/32x32/rotate-top-left-disabled.png</file>
<file>icon/32x32/rotate-bottom-right-disabled@2x.png</file>
<file>icon/32x32/rotate-bottom-right-disabled.png</file>
<file>icon/32x32/rotate-bottom-left-disabled@2x.png</file>
<file>icon/32x32/rotate-bottom-left-disabled.png</file>
<file>icon/32x32/expand2-disabled@2x.png</file>
<file>icon/32x32/expand2-disabled.png</file>
<file>icon/32x32/expand1-disabled@2x.png</file>
<file>icon/32x32/expand1-disabled.png</file>
<file>icon/32x32/double-arrow-vertical-disabled@2x.png</file>
<file>icon/32x32/double-arrow-vertical-disabled.png</file>
<file>icon/32x32/double-arrow-horizontal-disabled@2x.png</file>
<file>icon/32x32/double-arrow-horizontal-disabled.png</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 634 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 501 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 758 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 575 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 484 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 899 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 609 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 599 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 612 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 606 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -0,0 +1 @@
<svg id="Capa_1" enable-background="new 0 0 512 512" height="512" viewBox="0 0 512 512" width="512" xmlns="http://www.w3.org/2000/svg"><g><g><path d="m502.681 198.27v68.85l-2.48 1.68-24.29 16.48-58.97-40-58.97 40-58.97-40-58.97 40-58.96-40-58.97 40-26.76-18.15v-219.75c0-22.03 17.85-39.88 39.87-39.88h176.7c15.88 0 67.31 43.85 112.77 90.03 41.48 42.15 78 86.24 78 100.74z" fill="#ddeafb"/><path d="m475.911 332.15 26.77-18.16v150.63c0 22.03-17.85 39.88-39.87 39.88h-327.6c-18.82 0-34.59-13.04-38.78-30.58l-.16-22.8-.93-135.78v-1.34l26.76 18.15 58.97-40 58.96 40 58.97-40 58.97 40 58.97-40z" fill="#ddeafb"/><path d="m502.681 198.27v68.85l-2.48 1.68c-15.77-94.08-100.61-101.12-129.94-130.45l54.42-40.82c41.48 42.15 78 86.24 78 100.74z" fill="#cbe2ff"/><path d="m311.906 7.5h-97.57c.11 0 .22.01.34.01 119.72 3 125.26 100.52 157.15 132.41l40.82-54.42c-42.15-41.48-86.24-78-100.74-78z" fill="#cbe2ff"/><path d="m502.681 198.276v16.868c0-35.514-28.798-64.312-64.312-64.312h-39.143c-22.019 0-39.877-17.858-39.877-39.877v-39.143c0-35.514-28.798-64.312-64.312-64.312h16.868c30.373 0 59.512 12.068 80.989 33.545l76.242 76.242c21.476 21.476 33.545 50.615 33.545 80.989z" fill="#bed8fb"/><circle cx="96.445" cy="141.864" fill="#dd636e" r="87.126"/><path d="m107.749 228.264c-3.7.48-7.48.73-11.31.73-48.12 0-87.12-39.01-87.12-87.13 0-48.11 39-87.12 87.12-87.12 3.83 0 7.61.25 11.31.73-42.78 5.54-75.82 42.11-75.82 86.39 0 44.29 33.04 80.86 75.82 86.4z" fill="#da4a54"/></g><g><path d="m510.181 198.276c0-32.598-12.693-63.244-35.741-86.292l-76.242-76.242c-23.05-23.049-53.695-35.742-86.293-35.742h-.006-176.7c-26.12 0-47.37 21.255-47.37 47.38v.257c-48.153 4.369-86.01 44.956-86.01 94.223 0 49.273 37.856 89.864 86.01 94.233v31.027c0 2.486 1.232 4.811 3.29 6.207l26.769 18.16c2.543 1.725 5.88 1.724 8.421 0l54.761-37.144 54.749 37.144c2.543 1.725 5.88 1.724 8.421 0l54.76-37.144 54.76 37.144c2.541 1.725 5.879 1.724 8.42 0l54.761-37.144 54.76 37.144c1.271.862 2.74 1.293 4.21 1.293s2.939-.431 4.21-1.293l26.76-18.15c2.058-1.396 3.29-3.721 3.29-6.207zm-122.591-151.928 76.242 76.242c12.185 12.184 21.069 26.788 26.205 42.729-13.069-13.549-31.401-21.988-51.669-21.988h-39.143c-17.853 0-32.377-14.524-32.377-32.377v-39.142c0-20.268-8.438-38.599-21.987-51.669 15.942 5.137 30.545 14.021 42.729 26.205zm88.319 229.87-54.76-37.144c-2.541-1.724-5.879-1.724-8.42 0l-54.761 37.144-54.76-37.144c-2.541-1.724-5.879-1.724-8.42 0l-54.76 37.144-54.749-37.144c-2.543-1.725-5.88-1.724-8.421 0l-54.761 37.144-19.27-13.072v-26.876c49.21-3.293 88.24-44.375 88.24-94.41 0-29.062-13.078-56.098-35.881-74.177-3.244-2.573-7.963-2.029-10.536 1.218-2.573 3.246-2.028 7.963 1.218 10.536 19.191 15.217 30.199 37.969 30.199 62.423 0 43.908-35.718 79.63-79.62 79.63-43.908 0-79.63-35.722-79.63-79.63 0-43.903 35.722-79.62 79.63-79.62 7.619 0 15.133 1.069 22.331 3.177 3.979 1.166 8.142-1.115 9.306-5.089 1.165-3.975-1.114-8.141-5.089-9.306-6.547-1.918-13.307-3.107-20.168-3.564v-.078c0-17.854 14.521-32.38 32.37-32.38h159.838c31.326 0 56.812 25.486 56.812 56.812v39.143c0 26.124 21.253 47.377 47.377 47.377h39.143c31.171 0 56.551 25.237 56.801 56.35v48.472z"/><path d="m507.608 308.351c-2.641-2.287-6.383-2.434-9.149-.558l-22.55 15.294-54.76-37.144c-2.541-1.725-5.878-1.724-8.421 0l-19.519 13.243c-3.399 2.306-4.586 6.937-2.382 10.403 2.279 3.586 7.05 4.555 10.543 2.187l15.569-10.563 54.76 37.144c2.541 1.725 5.879 1.724 8.42 0l15.05-10.208v136.471c0 17.883-14.497 32.38-32.38 32.38h-327.59c-.462 0-.921-.01-1.379-.029-16.775-.699-29.846-14.883-29.961-31.673l-.941-137.098 14.97 10.156c2.543 1.725 5.88 1.724 8.421 0l54.761-37.144 54.749 37.144c2.543 1.725 5.88 1.724 8.421 0l54.76-37.144 54.76 37.144c2.54 1.724 5.877 1.724 8.419.001l11.172-7.575c3.399-2.304 4.586-6.933 2.384-10.399-2.279-3.587-7.052-4.559-10.543-2.192l-7.221 4.896-54.761-37.145c-2.541-1.724-5.879-1.724-8.42 0l-54.76 37.144-54.749-37.144c-2.543-1.725-5.88-1.724-8.421 0l-54.761 37.144-22.379-15.18c-1.84-1.248-4.138-1.747-6.287-1.175-3.377.899-5.604 3.914-5.604 7.259v1.402l1.09 154.58c0 17.853 14.019 42.029 46.28 42.029h327.6c26.162 0 47.37-21.208 47.37-47.37v-150.416c0-2.225-.879-4.407-2.561-5.864z"/><path d="m131.2 96.501-34.755 34.755-34.756-34.755c-2.93-2.929-7.678-2.929-10.607 0s-2.929 7.677 0 10.606l34.756 34.756-34.756 34.757c-2.929 2.929-2.929 7.677 0 10.606 1.465 1.465 3.385 2.197 5.304 2.197s3.839-.732 5.304-2.197l34.755-34.755 34.755 34.755c1.465 1.465 3.385 2.197 5.304 2.197s3.839-.732 5.304-2.197c2.929-2.929 2.929-7.677 0-10.606l-34.756-34.756 34.756-34.756c2.929-2.929 2.929-7.677 0-10.606-2.93-2.93-7.678-2.93-10.608-.001z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

View file

@ -92,6 +92,8 @@ Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingDockWidgetToolOptionsActive,
(QLatin1String("dockWidget/toolOptionsActive")))
Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingDockWidgetPatternMessagesActive,
(QLatin1String("dockWidget/patternMessagesActive")))
Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingDockWidgetBackgroundImagesActive,
(QLatin1String("dockWidget/backgroundImagesActive")))
Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingPatternMessagesFontSize, (QLatin1String("font/patternMessagesSize")))
Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingSearchHistoryHistory, (QLatin1String("searchHistory/history")))
@ -621,6 +623,24 @@ void VValentinaSettings::SetDockWidgetPatternMessagesActive(bool value)
setValue(*settingDockWidgetPatternMessagesActive, value);
}
//---------------------------------------------------------------------------------------------------------------------
bool VValentinaSettings::IsDockWidgetBackgroundImagesActive() const
{
return value(*settingDockWidgetBackgroundImagesActive, GetDefDockWidgetBackgroundImagesActive()).toBool();
}
//---------------------------------------------------------------------------------------------------------------------
bool VValentinaSettings::GetDefDockWidgetBackgroundImagesActive()
{
return false;
}
//---------------------------------------------------------------------------------------------------------------------
void VValentinaSettings::SetDockWidgetBackgroundImagesActive(bool value)
{
setValue(*settingDockWidgetBackgroundImagesActive, value);
}
//---------------------------------------------------------------------------------------------------------------------
int VValentinaSettings::GetPatternMessageFontSize(int fontSizeDef) const
{

View file

@ -153,6 +153,10 @@ public:
static bool GetDefDockWidgetPatternMessagesActive();
void SetDockWidgetPatternMessagesActive(bool value);
bool IsDockWidgetBackgroundImagesActive() const;
static bool GetDefDockWidgetBackgroundImagesActive();
void SetDockWidgetBackgroundImagesActive(bool value);
int GetPatternMessageFontSize(int fontSizeDef) const;
static int GetDefMinPatternMessageFontSize();
static int GetDefMaxPatternMessageFontSize();

View file

@ -20,61 +20,95 @@
#include "vboolproperty.h"
#include <QCheckBox>
#include <QCoreApplication>
#include <QFlags>
#include <QObject>
#include "../vproperty_p.h"
QVariant VPE::VBoolProperty::TrueText;
QVariant VPE::VBoolProperty::FalseText;
VPE::VBoolProperty::VBoolProperty(const QString& name) :
VProperty(name, QVariant::Bool)
{
d_ptr->VariantValue.setValue(false);
d_ptr->VariantValue.convert(QVariant::Bool);
// I'm not sure, how Qt handles the translations...
if (TrueText.isNull())
{
TrueText = tr("True");
}
if (FalseText.isNull())
{
FalseText = tr("False");
}
}
//! Get the data how it should be displayed
QVariant VPE::VBoolProperty::data (int column, int role) const
auto VPE::VBoolProperty::data (int column, int role) const -> QVariant
{
if (column == DPC_Data && (Qt::DisplayRole == role || Qt::EditRole == role))
auto* tmpEditor = qobject_cast<QCheckBox*>(VProperty::d_ptr->editor);
if (column == DPC_Data && Qt::DisplayRole == role)
{
return d_ptr->VariantValue.toBool() ? TrueText : FalseText;
return tmpEditor->checkState();
}
if (column == DPC_Data && Qt::CheckStateRole == role)
if (column == DPC_Data && Qt::EditRole == role)
{
return d_ptr->VariantValue.toBool() ? Qt::Checked : Qt::Unchecked;
return VProperty::d_ptr->VariantValue;
}
else
return VProperty::data(column, role);
return VProperty::data(column, role);
}
bool VPE::VBoolProperty::setData(const QVariant &data, int role)
auto VPE::VBoolProperty::createEditor(QWidget *parent, const QStyleOptionViewItem &options,
const QAbstractItemDelegate *delegate) -> QWidget *
{
if (Qt::CheckStateRole == role)
Q_UNUSED(options)
Q_UNUSED(delegate)
auto* tmpEditor = new QCheckBox(parent);
tmpEditor->setCheckState(d_ptr->VariantValue.toBool() ? Qt::Checked : Qt::Unchecked);
connect(tmpEditor, &QCheckBox::stateChanged, this, &VBoolProperty::StateChanged);
VProperty::d_ptr->editor = tmpEditor;
return VProperty::d_ptr->editor;
}
auto VPE::VBoolProperty::setEditorData(QWidget *editor) -> bool
{
if (!editor)
{
d_ptr->VariantValue = (Qt::Checked == static_cast<Qt::CheckState>(data.toInt()));
return false;
}
auto* tmpEditor = qobject_cast<QCheckBox*>(editor);
if (tmpEditor)
{
tmpEditor->blockSignals(true);
tmpEditor->setCheckState(d_ptr->VariantValue.toBool() ? Qt::Checked : Qt::Unchecked);
tmpEditor->blockSignals(false);
return true;
}
return false;
}
auto VPE::VBoolProperty::getEditorData(const QWidget *editor) const -> QVariant
{
const auto* tmpEditor = qobject_cast<const QCheckBox*>(editor);
if (tmpEditor)
{
return tmpEditor->checkState() == Qt::Checked ? Qt::Checked : Qt::Unchecked;
}
return {0};
}
void VPE::VBoolProperty::setValue(const QVariant &value)
{
VProperty::d_ptr->VariantValue = value;
VProperty::d_ptr->VariantValue.convert(QVariant::Bool);
if (VProperty::d_ptr->editor != nullptr)
{
setEditorData(VProperty::d_ptr->editor);
}
}
//! Returns item flags
Qt::ItemFlags VPE::VBoolProperty::flags(int column) const
auto VPE::VBoolProperty::flags(int column) const -> Qt::ItemFlags
{
if (column == DPC_Data)
{
@ -84,12 +118,18 @@ Qt::ItemFlags VPE::VBoolProperty::flags(int column) const
return VProperty::flags(column);
}
QString VPE::VBoolProperty::type() const
auto VPE::VBoolProperty::type() const -> QString
{
return "bool";
}
VPE::VProperty *VPE::VBoolProperty::clone(bool include_children, VProperty *container) const
auto VPE::VBoolProperty::clone(bool include_children, VProperty *container) const -> VPE::VProperty *
{
return VProperty::clone(include_children, container ? container : new VBoolProperty(getName()));
}
void VPE::VBoolProperty::StateChanged()
{
auto *event = new UserChangeEvent();
QCoreApplication::postEvent ( VProperty::d_ptr->editor, event );
}

View file

@ -48,36 +48,43 @@ public:
explicit VBoolProperty(const QString& name);
//! Destructor
virtual ~VBoolProperty() override {}
~VBoolProperty() override = default;
//! Get the data how it should be displayed
virtual QVariant data (int column = DPC_Name, int role = Qt::DisplayRole) const override;
auto data(int column = DPC_Name, int role = Qt::DisplayRole) const -> QVariant override;
//! This is used by the model to set the data
//! \param data The data to set
//! \param role The role. Default is Qt::EditRole
//! \return Returns true, if the data was changed, false if not.
virtual bool setData (const QVariant& data, int role = Qt::EditRole) override;
//! Returns an editor widget, or NULL if it doesn't supply one
//! \param parent The widget to which the editor will be added as a child
//! \options Render options
//! \delegate A pointer to the QAbstractItemDelegate requesting the editor. This can be used to connect signals and
//! slots.
auto createEditor(QWidget* parent, const QStyleOptionViewItem& options,
const QAbstractItemDelegate* delegate) -> QWidget* override;
//! Sets the property's data to the editor (returns false, if the standard delegate should do that)
auto setEditorData(QWidget* editor) -> bool override;
//! Gets the data from the widget
auto getEditorData(const QWidget* editor) const -> QVariant override;
//! Sets the value of the property
void setValue(const QVariant& value) override;
//! Returns item flags
virtual Qt::ItemFlags flags(int column = DPC_Name) const override;
auto flags(int column = DPC_Name) const -> Qt::ItemFlags override;
//! Returns a string containing the type of the property
virtual QString type() const override;
auto type() const -> QString override;
//! Clones this property
//! \param include_children Indicates whether to also clone the children
//! \param container If a property is being passed here, no new VProperty is being created but instead it is tried
//! to fill all the data into container. This can also be used when subclassing this function.
//! \return Returns the newly created property (or container, if it was not NULL)
virtual VProperty* clone(bool include_children = true, VProperty* container = NULL) const override;
auto clone(bool include_children = true, VProperty* container = NULL) const -> VProperty* override;
protected:
//! The (translatable) text displayed when the property is set to true (default: "True")
static QVariant TrueText;
//! The (translatable) text displayed when the property is set to false (default: "False")
static QVariant FalseText;
public slots:
void StateChanged();
private:
Q_DISABLE_COPY(VBoolProperty)
@ -85,6 +92,6 @@ private:
QT_WARNING_POP
}
} // namespace VPE
#endif // VBOOLPROPERTY_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,185 @@
/************************************************************************
**
** @file vbackgroundimagecontrols.h
** @author Roman Telezhynskyi <dismine(at)gmail.com>
** @date 17 1, 2022
**
** @brief
** @copyright
** This source code is part of the Valentina project, a pattern making
** program, whose allow create and modeling patterns of clothing.
** Copyright (C) 2022 Valentina project
** <https://gitlab.com/smart-pattern/valentina> All Rights Reserved.
**
** Valentina is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Valentina 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
**
*************************************************************************/
#ifndef VBACKGROUNDIMAGECONTROLS_H
#define VBACKGROUNDIMAGECONTROLS_H
#include <QGraphicsObject>
#include <QUuid>
#include "../vmisc/def.h"
#include "../ifc/xml/vbackgroundpatternimage.h"
#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
#include "../vmisc/defglobal.h"
#endif // QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
class VAbstractPattern;
class QScreen;
enum class BITransformationType {Scale, Rotate, Unknown};
enum class BIHandleCorner : int
{
Invalid,
TopLeft,
Top,
TopRight,
Right,
BottomRight,
Bottom,
BottomLeft,
Left
};
enum class BIHandleCornerType
{
ScaleTopLeftBottomRight,
ScaleTopBottom,
ScaleTopRightBottomLeft,
ScaleRightLeft,
RotateTopLeft,
RotateTopRight,
RotateBottomRight,
RotateBottomLeft
};
class VBackgroundImageControls : public QGraphicsObject
{
Q_OBJECT
public:
explicit VBackgroundImageControls(VAbstractPattern *doc, QGraphicsItem * parent = nullptr);
~VBackgroundImageControls() override = default;
auto type() const -> int override {return Type;}
enum { Type = UserType + static_cast<int>(Tool::BackgroundImageControls)};
auto Id() const -> const QUuid &;
signals:
void ActiveImageChanged(const QUuid &id);
public slots:
void ActivateControls(const QUuid &id);
void DeactivateControls(QGraphicsItem* pItem);
void UpdateControls();
protected:
auto boundingRect() const -> QRectF override;
auto shape() const -> QPainterPath override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
void mousePressEvent(QGraphicsSceneMouseEvent * event) override;
void mouseMoveEvent(QGraphicsSceneMouseEvent * event) override;
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override;
void hoverMoveEvent(QGraphicsSceneHoverEvent *event) override;
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override;
private slots:
void ScreenChanged();
private:
Q_DISABLE_COPY_MOVE(VBackgroundImageControls)
QUuid m_id{};
VAbstractPattern *m_doc;
VBackgroundPatternImage m_image{};
BITransformationType m_tranformationType{BITransformationType::Unknown};
QMap<BIHandleCornerType, QPixmap> m_handlePixmaps{};
QMap<BIHandleCornerType, QPixmap> m_handleHoverPixmaps{};
QMap<BIHandleCornerType, QPixmap> m_handleDisabledPixmaps{};
QMap<BIHandleCornerType, QPainterPath> m_handlePaths{};
BIHandleCorner m_handleCornerHover{BIHandleCorner::Invalid};
bool m_controlsVisible{true};
bool m_allowChangeMerge{false};
bool m_transformationApplied{false};
QPointF m_scaleDiff{};
QTransform m_originalMatrix{};
QRectF m_imageBoundingRect{};
QRectF m_imageScreenBoundingRect{};
QPointF m_rotationStartPoint{};
bool m_showOrigin{false};
QPointF m_originPos{};
void InitPixmaps();
auto TopLeftHandlerPosition() const -> QPointF;
auto TopHandlerPosition() const -> QPointF;
auto TopRightHandlerPosition() const -> QPointF;
auto RightHandlerPosition() const -> QPointF;
auto BottomRightHandlerPosition() const -> QPointF;
auto BottomHandlerPosition() const -> QPointF;
auto BottomLeftHandlerPosition() const -> QPointF;
auto LeftHandlerPosition() const -> QPointF;
auto ControllerPath(BIHandleCornerType type, QPointF pos) const -> QPainterPath;
auto ScaleTopLeftControl() const -> QPainterPath;
auto ScaleTopControl() const -> QPainterPath;
auto ScaleTopRightControl() const -> QPainterPath;
auto ScaleRightControl() const -> QPainterPath;
auto ScaleBottomRightControl() const -> QPainterPath;
auto ScaleBottomControl() const -> QPainterPath;
auto ScaleBottomLeftControl() const -> QPainterPath;
auto ScaleLeftControl() const -> QPainterPath;
auto RotateTopLeftControl() const -> QPainterPath;
auto RotateTopRightControl() const -> QPainterPath;
auto RotateBottomRightControl() const -> QPainterPath;
auto RotateBottomLeftControl() const -> QPainterPath;
auto ScaleByTopLeft(QGraphicsSceneMouseEvent * event) const -> QTransform;
auto ScaleByTop(QGraphicsSceneMouseEvent * event) const -> QTransform;
auto ScaleByTopRight(QGraphicsSceneMouseEvent * event) const -> QTransform;
auto ScaleByRight(QGraphicsSceneMouseEvent * event) const -> QTransform;
auto ScaleByBottomRight(QGraphicsSceneMouseEvent * event) const -> QTransform;
auto ScaleByBottom(QGraphicsSceneMouseEvent * event) const -> QTransform;
auto ScaleByBottomLeft(QGraphicsSceneMouseEvent * event) const -> QTransform;
auto ScaleByLeft(QGraphicsSceneMouseEvent * event) const -> QTransform;
auto Handles() const -> QPainterPath;
auto ControllersRect() const -> QRectF;
auto SelectedHandleCorner(const QPointF &pos) const -> BIHandleCorner;
auto HandlerPixmap(bool hover, BIHandleCornerType type) const -> QPixmap;
void ShowOrigin(const QPointF &pos);
auto OriginCircle1() const -> QPainterPath;
auto OriginCircle2() const -> QPainterPath;
auto OriginPath() const -> QPainterPath;
void ScaleImage(QGraphicsSceneMouseEvent * event);
void RotateImage(QGraphicsSceneMouseEvent * event);
};
#endif // VBACKGROUNDIMAGECONTROLS_H

View file

@ -0,0 +1,734 @@
/************************************************************************
**
** @file vbackgroundimageitem.cpp
** @author Roman Telezhynskyi <dismine(at)gmail.com>
** @date 13 1, 2022
**
** @brief
** @copyright
** This source code is part of the Valentina project, a pattern making
** program, whose allow create and modeling patterns of clothing.
** Copyright (C) 2022 Valentina project
** <https://gitlab.com/smart-pattern/valentina> All Rights Reserved.
**
** Valentina is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Valentina 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
**
*************************************************************************/
#include "vbackgroundimageitem.h"
#include "../vwidgets/global.h"
#include "../vmisc/vabstractvalapplication.h"
#include "../vwidgets/vmaingraphicsview.h"
#include "../ifc/xml/vabstractpattern.h"
#include "../../undocommands/image/movebackgroundimage.h"
#include "../../undocommands/image/holdbackgroundimage.h"
#include "../../undocommands/image/rotatebackgroundimage.h"
#include "../../undocommands/image/scalebackgroundimage.h"
#include "../../undocommands/image/renamebackgroundimage.h"
#include "../../undocommands/image/hidebackgroundimage.h"
#include "../../undocommands/image/resetbackgroundimage.h"
#include "../toolsdef.h"
#include <QUndoStack>
#include <QGraphicsView>
#include <QGraphicsSceneMouseEvent>
#include <QMenu>
#include <QGraphicsDropShadowEffect>
#include <QMessageBox>
#include <QKeyEvent>
//---------------------------------------------------------------------------------------------------------------------
VBackgroundImageItem::VBackgroundImageItem(const VBackgroundPatternImage &image, VAbstractPattern *doc,
QGraphicsItem *parent)
: QGraphicsObject{parent},
m_image(image),
m_doc(doc)
{
SCASSERT(doc != nullptr)
setAcceptHoverEvents(true);
connect(doc, &VAbstractPattern::BackgroundImageTransformationChanged, this,
&VBackgroundImageItem::ImageTransformationChanged);
connect(doc, &VAbstractPattern::BackgroundImageHoldChanged, this, &VBackgroundImageItem::HoldChanged);
connect(doc, &VAbstractPattern::BackgroundImageVisibilityChanged, this, &VBackgroundImageItem::VisibilityChanged);
connect(doc, &VAbstractPattern::BackgroundImageNameChanged, this, &VBackgroundImageItem::NameChanged);
connect(doc, &VAbstractPattern::BackgroundImagesHoldChanged, this, &VBackgroundImageItem::UpdateHoldState);
connect(doc, &VAbstractPattern::BackgroundImagesVisibilityChanged, this,
&VBackgroundImageItem::UpdateVisibilityState);
connect(doc, &VAbstractPattern::BackgroundImagesZValueChanged, this, &VBackgroundImageItem::ZValueChanged);
connect(doc, &VAbstractPattern::BackgroundImagePositionChanged, this, &VBackgroundImageItem::PositionChanged);
InitImage();
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundImageItem::Image() const -> const VBackgroundPatternImage &
{
return m_image;
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::SetImage(const VBackgroundPatternImage &newImage)
{
prepareGeometryChange();
m_image = newImage;
InitImage();
m_stale = true;
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundImageItem::pen() -> QPen
{
return {QBrush(), 1.0};
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundImageItem::name() const -> QString
{
return m_image.Name();
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::setName(const QString &newName)
{
VAbstractApplication::VApp()->getUndoStack()->push(new RenameBackgroundImage(m_image.Id(), newName, m_doc));
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundImageItem::IsHold() const -> bool
{
return m_image.Hold();
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::SetHold(bool hold)
{
VAbstractApplication::VApp()->getUndoStack()->push(new HoldBackgroundImage(m_image.Id(), hold, m_doc));
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundImageItem::IsVisible() const -> bool
{
return m_image.Visible();
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::SetVisible(bool visible)
{
VAbstractApplication::VApp()->getUndoStack()->push(new HideBackgroundImage(m_image.Id(), not visible, m_doc));
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option)
Q_UNUSED(widget)
if (m_showHover)
{
painter->save();
QBrush brush(QColor(177, 216, 250, 25));
painter->setBrush(brush);
painter->drawRect(boundingRect());
painter->restore();
}
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::PositionChanged(QUuid id)
{
if (m_image.Id() != id)
{
return;
}
QTransform oldMatrix = m_image.Matrix();
m_image = m_doc->GetBackgroundImage(id);
QTransform newMatrix = m_image.Matrix();
if (not VFuzzyComparePossibleNulls(oldMatrix.m31(), newMatrix.m31()) ||
not VFuzzyComparePossibleNulls(oldMatrix.m32(), newMatrix.m32()))
{
prepareGeometryChange();
update();
}
emit UpdateControls();
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::ImageTransformationChanged(QUuid id)
{
if (m_image.Id() != id)
{
return;
}
prepareGeometryChange();
m_image = m_doc->GetBackgroundImage(id);
emit UpdateControls();
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::HoldChanged(QUuid id)
{
if (m_image.Id() != id)
{
return;
}
UpdateHoldState();
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::VisibilityChanged(QUuid id)
{
if (m_image.Id() != id)
{
return;
}
UpdateVisibilityState();
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::NameChanged(QUuid id)
{
if (m_image.Id() != id)
{
return;
}
m_image = m_doc->GetBackgroundImage(id);
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::EnableSelection(bool enable)
{
m_selectable = enable;
setFlag(QGraphicsItem::ItemSendsGeometryChanges, m_selectable && not m_image.Hold());
setFlag(QGraphicsItem::ItemIsFocusable, m_selectable && not m_image.Hold());
if (not m_selectable)
{
emit ActivateControls(QUuid());
}
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::DeleteFromMenu()
{
DeleteToolWithConfirm();
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundImageItem::itemChange(GraphicsItemChange change, const QVariant &value) -> QVariant
{
if (change == ItemPositionChange && (scene() != nullptr))
{
// Each time we move something we call recalculation scene rect. In some cases this can cause moving
// objects positions. And this cause infinite redrawing. That's why we wait the finish of saving the last move.
static bool changeFinished = true;
if (changeFinished)
{
changeFinished = false;
// value - this is new position.
const QPointF newPos = value.toPointF();
const QPointF diff = newPos - m_lastMoveDistance;
auto *command = new MoveBackgroundImage(m_image.Id(), diff.x(), diff.y(), m_doc, m_allowChangeMerge);
VAbstractApplication::VApp()->getUndoStack()->push(command);
const QList<QGraphicsView *> viewList = scene()->views();
if (not viewList.isEmpty())
{
if (auto *view = qobject_cast<VMainGraphicsView *>(viewList.at(0)))
{
view->EnsureItemVisibleWithDelay(this, VMainGraphicsView::scrollDelay);
}
}
changeFinished = true;
m_lastMoveDistance = newPos;
}
return pos();
}
return value;
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if (not m_selectable)
{
event->ignore();
return;
}
if (not Image().Hold())
{
if (flags() & QGraphicsItem::ItemIsMovable)
{
if (event->button() == Qt::LeftButton && event->type() != QEvent::GraphicsSceneMouseDoubleClick)
{
SetItemOverrideCursor(this, cursorArrowCloseHand, 1, 1);
}
}
if (event->button() == Qt::LeftButton && event->type() != QEvent::GraphicsSceneMouseDoubleClick)
{
m_lastMoveDistance = QPointF();
emit Selected(m_image.Id());
event->accept();
}
else
{
QGraphicsObject::mousePressEvent(event);
}
}
else
{
if (event->button() == Qt::LeftButton && event->type() != QEvent::GraphicsSceneMouseDoubleClick)
{
emit ActivateControls(m_image.Id());
}
QGraphicsObject::mousePressEvent(event);
}
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsObject::mouseMoveEvent(event);
m_allowChangeMerge = true;
m_wasMoved = true;
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if (event->button() == Qt::LeftButton && event->type() != QEvent::GraphicsSceneMouseDoubleClick &&
(flags() & QGraphicsItem::ItemIsMovable))
{
m_lastMoveDistance = QPointF();
SetItemOverrideCursor(this, cursorArrowOpenHand, 1, 1);
m_allowChangeMerge = false;
if (not m_wasMoved && m_selectable)
{
emit ActivateControls(m_image.Id());
}
m_wasMoved = false;
}
QGraphicsObject::mouseReleaseEvent(event);
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
if (m_selectable && flags() & QGraphicsItem::ItemIsMovable)
{
m_showHover = true;
SetItemOverrideCursor(this, cursorArrowOpenHand, 1, 1);
}
else
{
setCursor(VAbstractValApplication::VApp()->getSceneView()->viewport()->cursor());
}
QGraphicsObject::hoverEnterEvent(event);
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
{
if (m_selectable && flags() & QGraphicsItem::ItemIsMovable)
{
SetItemOverrideCursor(this, cursorArrowOpenHand, 1, 1);
}
else
{
setCursor(VAbstractValApplication::VApp()->getSceneView()->viewport()->cursor());
}
QGraphicsObject::hoverMoveEvent(event);
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
m_showHover = false;
setCursor(VAbstractValApplication::VApp()->getSceneView()->viewport()->cursor());
QGraphicsObject::hoverLeaveEvent(event);
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
if (not m_selectable)
{
return;
}
QMenu menu;
QAction *holdOption = menu.addAction(tr("Hold"));
holdOption->setCheckable(true);
holdOption->setChecked(m_image.Hold());
QAction *actionVisible = menu.addAction(tr("Visible"));
actionVisible->setCheckable(true);
actionVisible->setChecked(m_image.Visible());
#if defined(Q_OS_MAC)
const QString actionShowTitle = tr("Show in Finder");
#else
const QString actionShowTitle = tr("Show in Explorer");
#endif
QAction *actionShow = menu.addAction(QIcon::fromTheme(QStringLiteral("system-search")), actionShowTitle);
actionShow->setVisible(false);
actionShow->setEnabled(QFileInfo::exists(m_image.FilePath()));
QAction *actionSaveAs = menu.addAction(QIcon::fromTheme(QStringLiteral("document-save-as")), tr("Save as …"));
actionSaveAs->setVisible(false);
if (not m_image.FilePath().isEmpty())
{
actionShow->setVisible(true);
}
else if (not m_image.ContentData().isEmpty())
{
actionSaveAs->setVisible(true);
}
QAction *actionReset = menu.addAction(tr("Reset transformation"));
actionReset->setEnabled(not m_image.Hold());
QAction *actionRemove = menu.addAction(QIcon::fromTheme(QStringLiteral("edit-delete")), tr("Delete"));
QAction *selectedAction = menu.exec(event->screenPos());
if (selectedAction == holdOption)
{
SetHold(selectedAction->isChecked());
}
else if (selectedAction == actionVisible)
{
SetVisible(selectedAction->isChecked());
}
else if (selectedAction == actionShow)
{
emit ShowImageInExplorer(m_image.Id());
}
else if (selectedAction == actionSaveAs)
{
emit SaveImage(m_image.Id());
}
else if (selectedAction == actionReset)
{
VAbstractApplication::VApp()->getUndoStack()->push(new ResetBackgroundImage(m_image.Id(), m_doc));
}
else if (selectedAction == actionRemove)
{
DeleteFromMenu();
}
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::keyPressEvent(QKeyEvent *event)
{
const int move = event->modifiers() & Qt::ShiftModifier ? 10 : 1;
if (event->key() == Qt::Key_Left)
{
TranslateImageOn(-move, 0);
event->accept();
return;
}
if (event->key() == Qt::Key_Right)
{
TranslateImageOn(move, 0);
event->accept();
return;
}
if (event->key() == Qt::Key_Up)
{
TranslateImageOn(0, -move);
event->accept();
return;
}
if (event->key() == Qt::Key_Down)
{
TranslateImageOn(0, move);
event->accept();
return;
}
int angle = 15;
if(event->modifiers() & Qt::ControlModifier)
{
angle = 90;
}
else if(event->modifiers() & Qt::AltModifier)
{
angle = 1;
}
if (event->key() == Qt::Key_BracketLeft)
{
RotateImageByAngle(angle);
event->accept();
return;
}
if (event->key() == Qt::Key_BracketRight)
{
RotateImageByAngle(-angle);
event->accept();
return;
}
if (event->key() == Qt::Key_Period || event->key() == Qt::Key_Greater)
{
if (event->modifiers() & Qt::ControlModifier)
{
ScaleImageByFactor(2);
}
else
{
ScaleImageByAdjustSize(2);
}
}
if (event->key() == Qt::Key_Comma || event->key() == Qt::Key_Less)
{
if (event->modifiers() & Qt::ControlModifier)
{
ScaleImageByFactor(0.5);
}
else
{
ScaleImageByAdjustSize(-2);
}
}
QGraphicsObject::keyPressEvent(event);
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::keyReleaseEvent(QKeyEvent *event)
{
if (not Image().Hold())
{
if (event->key() == Qt::Key_Delete)
{
if (ConfirmDeletion() == QMessageBox::Yes)
{
DeleteToolWithConfirm(false);
event->accept();
return;
}
}
else if (event->key() == Qt::Key_Left ||
event->key() == Qt::Key_Right ||
event->key() == Qt::Key_Up ||
event->key() == Qt::Key_Down ||
event->key() == Qt::Key_BracketLeft ||
event->key() == Qt::Key_BracketRight ||
event->key() == Qt::Key_Period ||
event->key() == Qt::Key_Greater ||
event->key() == Qt::Key_Comma ||
event->key() == Qt::Key_Less)
{
if (not event->isAutoRepeat())
{
m_allowChangeMerge = false;
}
event->accept();
return;
}
}
QGraphicsObject::keyReleaseEvent(event);
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundImageItem::Stale() const -> bool
{
return m_stale;
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::MakeFresh() const
{
m_stale = false;
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::DeleteToolWithConfirm(bool ask)
{
if (ask)
{
if (ConfirmDeletion() == QMessageBox::No)
{
return;
}
}
emit ActivateControls(QUuid());
emit DeleteImage(m_image.Id());
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::UpdateHoldState()
{
m_image = m_doc->GetBackgroundImage(m_image.Id());
setFlag(QGraphicsItem::ItemIsMovable, not m_image.Hold());
setFlag(QGraphicsItem::ItemSendsGeometryChanges, not m_image.Hold());
setFlag(QGraphicsItem::ItemIsFocusable, not m_image.Hold());// For keyboard input focus
emit UpdateControls();
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::UpdateVisibilityState()
{
m_image = m_doc->GetBackgroundImage(m_image.Id());
setVisible(m_image.Visible());
if (not m_image.Visible())
{
emit ActivateControls(QUuid());
}
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::ZValueChanged()
{
m_image = m_doc->GetBackgroundImage(m_image.Id());
SetupZValue();
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::InitImage()
{
SetupZValue();
setFlag(QGraphicsItem::ItemIsMovable, not m_image.Hold());
setFlag(QGraphicsItem::ItemSendsGeometryChanges, not m_image.Hold());
setFlag(QGraphicsItem::ItemIsFocusable, not m_image.Hold());// For keyboard input focus
setVisible(m_image.Visible());
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::TranslateImageOn(qreal dx, qreal dy)
{
auto *command = new MoveBackgroundImage(m_image.Id(), dx, dy, m_doc, m_allowChangeMerge);
VAbstractApplication::VApp()->getUndoStack()->push(command);
UpdateSceneRect();
m_allowChangeMerge = true;
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::RotateImageByAngle(qreal angle)
{
QTransform imageMatrix = m_image.Matrix();
QPointF originPos = m_image.BoundingRect().center();
QTransform m;
m.translate(originPos.x(), originPos.y());
m.rotate(-angle);
m.translate(-originPos.x(), -originPos.y());
imageMatrix *= m;
auto *command = new RotateBackgroundImage(m_image.Id(), imageMatrix, m_doc, m_allowChangeMerge);
VAbstractApplication::VApp()->getUndoStack()->push(command);
UpdateSceneRect();
m_allowChangeMerge = true;
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::ScaleImageByAdjustSize(qreal value)
{
QRectF rect = m_image.BoundingRect();
QRectF adjusted = rect;
adjusted.adjust(-value, -value, value, value);
qreal factor = adjusted.width() / rect.width();
ScaleImageByFactor(factor);
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::ScaleImageByFactor(qreal factor)
{
QTransform imageMatrix = m_image.Matrix();
QPointF originPos = m_image.BoundingRect().center();
QTransform m;
m.translate(originPos.x(), originPos.y());
m.scale(factor, factor);
m.translate(-originPos.x(), -originPos.y());
imageMatrix *= m;
auto *command = new ScaleBackgroundImage(m_image.Id(), imageMatrix, m_doc, m_allowChangeMerge);
VAbstractApplication::VApp()->getUndoStack()->push(command);
UpdateSceneRect();
m_allowChangeMerge = true;
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::UpdateSceneRect()
{
const QList<QGraphicsView *> viewList = scene()->views();
if (not viewList.isEmpty())
{
if (auto *view = qobject_cast<VMainGraphicsView *>(viewList.at(0)))
{
setFlag(QGraphicsItem::ItemSendsGeometryChanges, false);
VMainGraphicsView::NewSceneRect(scene(), view);
setFlag(QGraphicsItem::ItemSendsGeometryChanges, not m_image.Hold());
}
}
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundImageItem::SetupZValue()
{
if (qFuzzyIsNull(m_image.ZValue()))
{
setZValue(-1);
}
else if (m_image.ZValue() > 0)
{
setZValue(-1 * m_image.ZValue() - 1);
}
else
{
setZValue(m_image.ZValue() - 1);
}
}

View file

@ -0,0 +1,133 @@
/************************************************************************
**
** @file vbackgroundimageitem.h
** @author Roman Telezhynskyi <dismine(at)gmail.com>
** @date 13 1, 2022
**
** @brief
** @copyright
** This source code is part of the Valentina project, a pattern making
** program, whose allow create and modeling patterns of clothing.
** Copyright (C) 2022 Valentina project
** <https://gitlab.com/smart-pattern/valentina> All Rights Reserved.
**
** Valentina is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Valentina 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
**
*************************************************************************/
#ifndef VBACKGROUNDIMAGEITEM_H
#define VBACKGROUNDIMAGEITEM_H
#include <QGraphicsObject>
#include "../ifc/xml/vbackgroundpatternimage.h"
#include "../vmisc/def.h"
#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
#include "../vmisc/defglobal.h"
#endif // QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
class VAbstractPattern;
class VBackgroundImageItem : public QGraphicsObject
{
Q_OBJECT
public:
VBackgroundImageItem(const VBackgroundPatternImage &image, VAbstractPattern *doc, QGraphicsItem *parent = nullptr);
~VBackgroundImageItem() override = default;
auto type() const -> int override {return Type;}
enum {Type = UserType + static_cast<int>(Tool::BackgroundImage)};
auto Image() const -> const VBackgroundPatternImage &;
void SetImage(const VBackgroundPatternImage &newImage);
static auto pen() -> QPen;
auto name() const -> QString;
void setName(const QString &newName);
auto IsHold() const -> bool;
void SetHold(bool hold);
auto IsVisible() const -> bool;
void SetVisible(bool visible);
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
signals:
void Selected(const QUuid &id);
void UpdateControls();
void ActivateControls(const QUuid &id);
void DeleteImage(const QUuid &id);
void ShowImageInExplorer(const QUuid &id);
void SaveImage(const QUuid &id);
public slots:
void PositionChanged(QUuid id);
void ImageTransformationChanged(QUuid id);
void HoldChanged(QUuid id);
void VisibilityChanged(QUuid id);
void NameChanged(QUuid id);
void EnableSelection(bool enable);
void DeleteFromMenu();
protected:
auto itemChange(GraphicsItemChange change, const QVariant &value) -> QVariant override;
void mousePressEvent( QGraphicsSceneMouseEvent * event) override;
void mouseMoveEvent ( QGraphicsSceneMouseEvent * event ) override;
void mouseReleaseEvent ( QGraphicsSceneMouseEvent * event ) override;
void hoverEnterEvent ( QGraphicsSceneHoverEvent * event ) override;
void hoverMoveEvent ( QGraphicsSceneHoverEvent * event ) override;
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override;
void contextMenuEvent ( QGraphicsSceneContextMenuEvent * event ) override;
void keyPressEvent(QKeyEvent *event) override;
void keyReleaseEvent(QKeyEvent * event) override;
auto Stale() const -> bool;
void MakeFresh() const;
void DeleteToolWithConfirm(bool ask = true);
auto Invalid() const -> bool;
void SetInvalid(bool newInvalid);
private slots:
void UpdateHoldState();
void UpdateVisibilityState();
void ZValueChanged();
private:
Q_DISABLE_COPY_MOVE(VBackgroundImageItem)
VBackgroundPatternImage m_image;
VAbstractPattern *m_doc;
mutable bool m_stale{true};
bool m_allowChangeMerge{false};
QPointF m_lastMoveDistance{};
bool m_wasMoved{false};
bool m_showHover{false};
bool m_selectable{true};
void InitImage();
void TranslateImageOn(qreal dx, qreal dy);
void RotateImageByAngle(qreal angle);
void ScaleImageByAdjustSize(qreal value);
void ScaleImageByFactor(qreal factor);
void UpdateSceneRect();
void SetupZValue();
};
#endif // VBACKGROUNDIMAGEITEM_H

View file

@ -0,0 +1,245 @@
/************************************************************************
**
** @file vbackgroundpixmapitem.cpp
** @author Roman Telezhynskyi <dismine(at)gmail.com>
** @date 15 1, 2022
**
** @brief
** @copyright
** This source code is part of the Valentina project, a pattern making
** program, whose allow create and modeling patterns of clothing.
** Copyright (C) 2022 Valentina project
** <https://gitlab.com/smart-pattern/valentina> All Rights Reserved.
**
** Valentina is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Valentina 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
**
*************************************************************************/
#include "vbackgroundpixmapitem.h"
#include <QBitmap>
#include <QBuffer>
#include <QImageReader>
#include <QPainter>
#include <QStyleOptionGraphicsItem>
extern auto qt_regionToPath(const QRegion &region) -> QPainterPath;
namespace
{
auto InvalidImage() -> QPixmap
{
QImageReader imageReader(QStringLiteral("://icon/svg/broken_path.svg"));
return std::move(QPixmap::fromImageReader(&imageReader));
}
}
//---------------------------------------------------------------------------------------------------------------------
VBackgroundPixmapItem::VBackgroundPixmapItem(const VBackgroundPatternImage &image, VAbstractPattern *doc,
QGraphicsItem *parent)
: VBackgroundImageItem(image, doc, parent)
{}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundPixmapItem::SetTransformationMode(Qt::TransformationMode mode)
{
m_transformationMode = mode;
update();
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundPixmapItem::boundingRect() const -> QRectF
{
QPixmap pixmap = Pixmap();
if (pixmap.isNull())
{
return {};
}
return Image().Matrix().mapRect(QRectF(QPointF(0, 0), pixmap.size() / pixmap.devicePixelRatio()));
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundPixmapItem::shape() const -> QPainterPath
{
if (!m_hasShape)
{
UpdateShape();
m_hasShape = true;
}
return Image().Matrix().map(m_shape);
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundPixmapItem::contains(const QPointF &point) const -> bool
{
return QGraphicsItem::contains(point);
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundPixmapItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
painter->setRenderHint(QPainter::SmoothPixmapTransform, (m_transformationMode == Qt::SmoothTransformation));
painter->save();
painter->setTransform(Image().Matrix(), true);
painter->drawPixmap(QPointF(), Pixmap());
painter->restore();
VBackgroundImageItem::paint(painter, option, widget);
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundPixmapItem::isObscuredBy(const QGraphicsItem *item) const -> bool
{
return QGraphicsItem::isObscuredBy(item);
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundPixmapItem::opaqueArea() const -> QPainterPath
{
return shape();
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundPixmapItem::ShapeMode() const -> enum ShapeMode
{
return m_shapeMode;
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundPixmapItem::SetShapeMode(enum ShapeMode mode)
{
if (m_shapeMode == mode)
{
return;
}
m_shapeMode = mode;
m_hasShape = false;
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundPixmapItem::supportsExtension(Extension extension) const -> bool
{
Q_UNUSED(extension);
return false;
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundPixmapItem::setExtension(Extension extension, const QVariant &variant)
{
Q_UNUSED(extension);
Q_UNUSED(variant);
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundPixmapItem::extension(const QVariant &variant) const -> QVariant
{
Q_UNUSED(variant);
return {};
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundPixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
SetTransformationMode(Qt::FastTransformation);
VBackgroundImageItem::mouseMoveEvent(event);
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundPixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
SetTransformationMode(Qt::SmoothTransformation);
VBackgroundImageItem::mouseReleaseEvent(event);
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundPixmapItem::UpdateShape() const
{
QPixmap pixmap = Pixmap();
m_shape = QPainterPath();
switch (m_shapeMode)
{
case ShapeMode::MaskShape:
{
QBitmap mask = pixmap.mask();
if (!mask.isNull())
{
m_shape = qt_regionToPath(QRegion(mask));
break;
}
Q_FALLTHROUGH();
}
case ShapeMode::BoundingRectShape:
m_shape.addRect(QRectF(0, 0, pixmap.width(), pixmap.height()));
break;
case ShapeMode::HeuristicMaskShape:
#ifndef QT_NO_IMAGE_HEURISTIC_MASK
m_shape = qt_regionToPath(QRegion(pixmap.createHeuristicMask()));
#else
m_shape.addRect(QRectF(0, 0, m_shape.width(), m_shape.height()));
#endif
break;
default:
break;
}
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundPixmapItem::Pixmap() const -> QPixmap
{
if (Stale())
{
m_pixmap = QPixmap();
VBackgroundPatternImage image = Image();
if (not image.IsValid())
{
m_pixmap = InvalidImage();
MakeFresh();
return m_pixmap;
}
if (not image.FilePath().isEmpty())
{
QImageReader imageReader(image.FilePath());
m_pixmap = QPixmap::fromImageReader(&imageReader);
if (m_pixmap.isNull())
{
m_pixmap = InvalidImage();
}
MakeFresh();
return m_pixmap;
}
if (not image.ContentData().isEmpty())
{
QByteArray array = QByteArray::fromBase64(image.ContentData());
QBuffer buffer(&array);
buffer.open(QIODevice::ReadOnly);
QImageReader imageReader(&buffer);
m_pixmap = QPixmap::fromImageReader(&imageReader);
if (m_pixmap.isNull())
{
m_pixmap = InvalidImage();
}
MakeFresh();
return m_pixmap;
}
}
return m_pixmap;
}

View file

@ -0,0 +1,88 @@
/************************************************************************
**
** @file vbackgroundpixmapitem.h
** @author Roman Telezhynskyi <dismine(at)gmail.com>
** @date 15 1, 2022
**
** @brief
** @copyright
** This source code is part of the Valentina project, a pattern making
** program, whose allow create and modeling patterns of clothing.
** Copyright (C) 2022 Valentina project
** <https://gitlab.com/smart-pattern/valentina> All Rights Reserved.
**
** Valentina is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Valentina 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
**
*************************************************************************/
#ifndef VBACKGROUNDPIXMAPITEM_H
#define VBACKGROUNDPIXMAPITEM_H
#include "vbackgroundimageitem.h"
#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
#include "../vmisc/defglobal.h"
#endif // QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
enum class ShapeMode
{
MaskShape,
BoundingRectShape,
HeuristicMaskShape
};
class VBackgroundPixmapItem : public VBackgroundImageItem
{
public:
VBackgroundPixmapItem(const VBackgroundPatternImage &image, VAbstractPattern *doc, QGraphicsItem *parent = nullptr);
~VBackgroundPixmapItem() override = default;
auto type() const -> int override {return Type;}
enum {Type = UserType + static_cast<int>(Tool::BackgroundPixmapImage)};
auto boundingRect() const -> QRectF override;
auto shape() const -> QPainterPath override;
auto contains(const QPointF &point) const -> bool override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
auto isObscuredBy(const QGraphicsItem *item) const -> bool override;
auto opaqueArea() const -> QPainterPath override;
auto ShapeMode() const -> ShapeMode;
void SetShapeMode(enum ShapeMode mode);
protected:
auto supportsExtension(Extension extension) const -> bool override;
void setExtension(Extension extension, const QVariant &variant) override;
auto extension(const QVariant &variant) const -> QVariant override;
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
private:
Q_DISABLE_COPY_MOVE(VBackgroundPixmapItem)
mutable QPixmap m_pixmap{};
Qt::TransformationMode m_transformationMode{Qt::SmoothTransformation};
enum ShapeMode m_shapeMode{ShapeMode::MaskShape};
mutable QPainterPath m_shape{};
mutable bool m_hasShape{false};
void SetTransformationMode(Qt::TransformationMode mode);
void UpdateShape() const;
auto Pixmap() const -> QPixmap;
};
#endif // VBACKGROUNDPIXMAPITEM_H

View file

@ -0,0 +1,123 @@
/************************************************************************
**
** @file vbackgroundsvgitem.cpp
** @author Roman Telezhynskyi <dismine(at)gmail.com>
** @date 15 1, 2022
**
** @brief
** @copyright
** This source code is part of the Valentina project, a pattern making
** program, whose allow create and modeling patterns of clothing.
** Copyright (C) 2022 Valentina project
** <https://gitlab.com/smart-pattern/valentina> All Rights Reserved.
**
** Valentina is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Valentina 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
**
*************************************************************************/
#include "vbackgroundsvgitem.h"
#include <QStyleOptionGraphicsItem>
#include <QSvgRenderer>
#include <QPen>
#include <QPainter>
//---------------------------------------------------------------------------------------------------------------------
VBackgroundSVGItem::VBackgroundSVGItem(const VBackgroundPatternImage &image, VAbstractPattern *doc,
QGraphicsItem *parent)
: VBackgroundImageItem(image, doc, parent),
m_renderer(new QSvgRenderer())
{
setCacheMode(QGraphicsItem::DeviceCoordinateCache);
QObject::connect(m_renderer, &QSvgRenderer::repaintNeeded, this, &VBackgroundSVGItem::RepaintItem);
}
//---------------------------------------------------------------------------------------------------------------------
VBackgroundSVGItem::~VBackgroundSVGItem()
{
delete m_renderer;
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundSVGItem::boundingRect() const -> QRectF
{
return Image().Matrix().mapRect(QRectF(QPointF(0, 0), Renderer()->defaultSize()));
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundSVGItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
QSvgRenderer *renderer = Renderer();
if (not renderer->isValid())
{
return;
}
painter->save();
painter->setTransform(Image().Matrix(), true);
renderer->render(painter, QRectF(QPointF(0, 0), renderer->defaultSize()));
painter->restore();
VBackgroundImageItem::paint(painter, option, widget);
}
//---------------------------------------------------------------------------------------------------------------------
void VBackgroundSVGItem::RepaintItem()
{
update();
}
//---------------------------------------------------------------------------------------------------------------------
auto VBackgroundSVGItem::Renderer() const -> QSvgRenderer *
{
if (Stale())
{
const QString brokenImage = QStringLiteral("://icon/svg/broken_path.svg");
m_renderer->load(brokenImage);
VBackgroundPatternImage image = Image();
if (not image.IsValid())
{
MakeFresh();
return m_renderer;
}
if (not image.FilePath().isEmpty())
{
m_renderer->load(image.FilePath());
if (not m_renderer->isValid())
{
m_renderer->load(brokenImage);
}
MakeFresh();
return m_renderer;
}
if (not image.ContentData().isEmpty())
{
m_renderer->load(QByteArray::fromBase64(image.ContentData()));
if (not m_renderer->isValid())
{
m_renderer->load(brokenImage);
}
MakeFresh();
return m_renderer;
}
}
return m_renderer;
}

View file

@ -0,0 +1,63 @@
/************************************************************************
**
** @file vbackgroundsvgitem.h
** @author Roman Telezhynskyi <dismine(at)gmail.com>
** @date 15 1, 2022
**
** @brief
** @copyright
** This source code is part of the Valentina project, a pattern making
** program, whose allow create and modeling patterns of clothing.
** Copyright (C) 2022 Valentina project
** <https://gitlab.com/smart-pattern/valentina> All Rights Reserved.
**
** Valentina is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Valentina 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
**
*************************************************************************/
#ifndef VBACKGROUNDSVGITEM_H
#define VBACKGROUNDSVGITEM_H
#include "vbackgroundimageitem.h"
#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
#include "../vmisc/defglobal.h"
#endif // QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
class QSvgRenderer;
class VBackgroundSVGItem : public VBackgroundImageItem
{
Q_OBJECT
public:
VBackgroundSVGItem(const VBackgroundPatternImage &image, VAbstractPattern *doc, QGraphicsItem *parent = nullptr);
~VBackgroundSVGItem() override;
auto type() const -> int override {return Type;}
enum {Type = UserType + static_cast<int>(Tool::BackgroundSVGImage)};
auto boundingRect() const -> QRectF override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
private slots:
void RepaintItem();
private:
Q_DISABLE_COPY_MOVE(VBackgroundSVGItem)
QSvgRenderer *m_renderer{nullptr};
auto Renderer() const -> QSvgRenderer *;
};
#endif // VBACKGROUNDSVGITEM_H

View file

@ -2,7 +2,11 @@
# This need for corect working file translations.pro
HEADERS += \
$$PWD/backgroundimage/vbackgroundimagecontrols.h \
$$PWD/backgroundimage/vbackgroundpixmapitem.h \
$$PWD/backgroundimage/vbackgroundsvgitem.h \
$$PWD/toolsdef.h \
$$PWD/backgroundimage/vbackgroundimageitem.h \
$$PWD/vdatatool.h \
$$PWD/vabstracttool.h \
$$PWD/tools.h \
@ -65,7 +69,11 @@ HEADERS += \
$$PWD/nodeDetails/vtoolplacelabel.h
SOURCES += \
$$PWD/backgroundimage/vbackgroundimagecontrols.cpp \
$$PWD/backgroundimage/vbackgroundpixmapitem.cpp \
$$PWD/backgroundimage/vbackgroundsvgitem.cpp \
$$PWD/toolsdef.cpp \
$$PWD/backgroundimage/vbackgroundimageitem.cpp \
$$PWD/vdatatool.cpp \
$$PWD/vabstracttool.cpp \
$$PWD/drawTools/toolpoint/toolsinglepoint/vtooltriangle.cpp \

View file

@ -29,16 +29,21 @@
#include "toolsdef.h"
#include <QBrush>
#include <QDialogButtonBox>
#include <QIcon>
#include <QMessageBox>
#include <QPainter>
#include <QPen>
#include <QPixmap>
#include <QRegularExpression>
#include <QVector>
#include <QStyle>
#include "../vgeometry/vgobject.h"
#include "../qmuparser/qmudef.h"
#include "../vpatterndb/vcontainer.h"
#include "../vpropertyexplorer/checkablemessagebox.h"
#include "../vmisc/vabstractvalapplication.h"
//---------------------------------------------------------------------------------------------------------------------
QVector<quint32> SourceToObjects(const QVector<SourceItem> &source)
@ -116,3 +121,28 @@ QMap<QString, QIcon> OperationLineStylesPics()
map.insert(TypeLineDefault, QIcon());
return map;
}
//---------------------------------------------------------------------------------------------------------------------
auto ConfirmDeletion() -> int
{
if (not VAbstractApplication::VApp()->Settings()->GetConfirmItemDelete())
{
return QMessageBox::Yes;
}
Utils::CheckableMessageBox msgBox(VAbstractValApplication::VApp()->getMainWindow());
msgBox.setWindowTitle(QObject::tr("Confirm deletion"));
msgBox.setText(QObject::tr("Do you really want to delete?"));
msgBox.setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No);
msgBox.setDefaultButton(QDialogButtonBox::No);
msgBox.setIconPixmap(QApplication::style()->standardIcon(QStyle::SP_MessageBoxQuestion).pixmap(32, 32) );
int dialogResult = msgBox.exec();
if (dialogResult == QDialog::Accepted)
{
VAbstractApplication::VApp()->Settings()->SetConfirmItemDelete(not msgBox.isChecked());
}
return dialogResult == QDialog::Accepted ? QMessageBox::Yes : QMessageBox::No;
}

View file

@ -60,4 +60,6 @@ bool SourceAliasValid(const SourceItem &item, const QSharedPointer<VGObject> &ob
QMap<QString, QIcon> OperationLineStylesPics();
int ConfirmDeletion();
#endif // TOOLSDEF_H

Some files were not shown because too many files have changed in this diff Show more