diff --git a/ChangeLog.txt b/ChangeLog.txt index a17a41f5a..bab27baa5 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -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. diff --git a/src/app/puzzle/scene/vpmaingraphicsview.cpp b/src/app/puzzle/scene/vpmaingraphicsview.cpp index aa9953346..9b1656320 100644 --- a/src/app/puzzle/scene/vpmaingraphicsview.cpp +++ b/src/app/puzzle/scene/vpmaingraphicsview.cpp @@ -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); diff --git a/src/app/valentina/core/vtooloptionspropertybrowser.cpp b/src/app/valentina/core/vtooloptionspropertybrowser.cpp index 2bd34452e..9faee2563 100644 --- a/src/app/valentina/core/vtooloptionspropertybrowser.cpp +++ b/src/app/valentina/core/vtooloptionspropertybrowser.cpp @@ -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 #include +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(Tool::LAST_ONE_DO_NOT_USE) == 55, "Not all tools were used in switch."); + Q_STATIC_ASSERT_X(static_cast(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(Tool::LAST_ONE_DO_NOT_USE) == 55, "Not all tools were used in switch."); + Q_STATIC_ASSERT_X(static_cast(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(Tool::LAST_ONE_DO_NOT_USE) == 55, "Not all tools were used in switch."); + Q_STATIC_ASSERT_X(static_cast(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 void VToolOptionsPropertyBrowser::AddPropertyCrossPoint(Tool *i, const QString &propertyName) @@ -719,6 +753,66 @@ void VToolOptionsPropertyBrowser::AddPropertyApproximationScale(const QString &p AddProperty(aScaleProperty, AttrAScale); } +//--------------------------------------------------------------------------------------------------------------------- +template +void VToolOptionsPropertyBrowser::SetName(VPE::VProperty *property) +{ + if (auto *i = qgraphicsitem_cast(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 +void VToolOptionsPropertyBrowser::SetHold(VPE::VProperty *property) +{ + if (auto *i = qgraphicsitem_cast(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 +void VToolOptionsPropertyBrowser::SetVisible(VPE::VProperty *property) +{ + if (auto *i = qgraphicsitem_cast(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 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(property); + break; + case 65: // AttrHold + SetHold(property); + break; + case 66: // AttrVisible + SetVisible(property); + break; + default: + qWarning()<<"Unknown property type. id = "<(property); + break; + case 65: // AttrHold + SetHold(property); + break; + case 66: // AttrVisible + SetVisible(property); + break; + default: + qWarning()<<"Unknown property type. id = "<GetNotes(), AttrNotes); } +//--------------------------------------------------------------------------------------------------------------------- +void VToolOptionsPropertyBrowser::ShowOptionsBackgroundPixmapItem(QGraphicsItem *item) +{ + auto *i = qgraphicsitem_cast(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(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(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(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; } diff --git a/src/app/valentina/core/vtooloptionspropertybrowser.h b/src/app/valentina/core/vtooloptionspropertybrowser.h index cee994701..489800011 100644 --- a/src/app/valentina/core/vtooloptionspropertybrowser.h +++ b/src/app/valentina/core/vtooloptionspropertybrowser.h @@ -66,6 +66,15 @@ private: void AddProperty(VPE::VProperty *property, const QString &id); void ShowItemOptions(QGraphicsItem *item); + template + void SetName(VPE::VProperty *property); + + template + void SetHold(VPE::VProperty *property); + + template + void SetVisible(VPE::VProperty *property); + template 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 diff --git a/src/app/valentina/dialogs/dialogaddbackgroundimage.cpp b/src/app/valentina/dialogs/dialogaddbackgroundimage.cpp new file mode 100644 index 000000000..406349c75 --- /dev/null +++ b/src/app/valentina/dialogs/dialogaddbackgroundimage.cpp @@ -0,0 +1,55 @@ +/************************************************************************ + ** + ** @file dialogaddbackgroundimage.cpp + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ +#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(); +} diff --git a/src/app/valentina/dialogs/dialogaddbackgroundimage.h b/src/app/valentina/dialogs/dialogaddbackgroundimage.h new file mode 100644 index 000000000..2fc3914e4 --- /dev/null +++ b/src/app/valentina/dialogs/dialogaddbackgroundimage.h @@ -0,0 +1,58 @@ +/************************************************************************ + ** + ** @file dialogaddbackgroundimage.h + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ +#ifndef DIALOGADDBACKGROUNDIMAGE_H +#define DIALOGADDBACKGROUNDIMAGE_H + +#include + +#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 diff --git a/src/app/valentina/dialogs/dialogaddbackgroundimage.ui b/src/app/valentina/dialogs/dialogaddbackgroundimage.ui new file mode 100644 index 000000000..da0fe874a --- /dev/null +++ b/src/app/valentina/dialogs/dialogaddbackgroundimage.ui @@ -0,0 +1,94 @@ + + + DialogAddBackgroundImage + + + + 0 + 0 + 204 + 105 + + + + Background image + + + + :/icon/64x64/icon64x64.png:/icon/64x64/icon64x64.png + + + + + + + + Name: + + + + + + + + + + + + Determine should an image built in or added as path to the file. + + + Built in + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + buttonBox + accepted() + DialogAddBackgroundImage + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + DialogAddBackgroundImage + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/app/valentina/dialogs/dialoghistory.cpp b/src/app/valentina/dialogs/dialoghistory.cpp index 20fc03cf7..06fe143bd 100644 --- a/src/app/valentina/dialogs/dialoghistory.cpp +++ b/src/app/valentina/dialogs/dialoghistory.cpp @@ -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(Tool::LAST_ONE_DO_NOT_USE) == 55, "Not all tools were used in history."); + Q_STATIC_ASSERT_X(static_cast(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; diff --git a/src/app/valentina/dialogs/dialogpatternproperties.cpp b/src/app/valentina/dialogs/dialogpatternproperties.cpp index 47f540e4f..3973c8f18 100644 --- a/src/app/valentina/dialogs/dialogpatternproperties.cpp +++ b/src/app/valentina/dialogs/dialogpatternproperties.cpp @@ -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 supportedFormats = QImageReader::supportedImageFormats(); - const QSet 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); diff --git a/src/app/valentina/dialogs/dialogs.pri b/src/app/valentina/dialogs/dialogs.pri index 192266995..cfeb9151c 100644 --- a/src/app/valentina/dialogs/dialogs.pri +++ b/src/app/valentina/dialogs/dialogs.pri @@ -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 \ diff --git a/src/app/valentina/dialogs/vwidgetbackgroundimages.cpp b/src/app/valentina/dialogs/vwidgetbackgroundimages.cpp new file mode 100644 index 000000000..c9182f036 --- /dev/null +++ b/src/app/valentina/dialogs/vwidgetbackgroundimages.cpp @@ -0,0 +1,1013 @@ +/************************************************************************ + ** + ** @file vwidgetbackgroundimages.cpp + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ +#include "vwidgetbackgroundimages.h" +#include "ui_vwidgetbackgroundimages.h" + +#include "../vmisc/def.h" +#include "../ifc/xml/vabstractpattern.h" +#include "../ifc/xml/vbackgroundpatternimage.h" +#include "../vtools/undocommands/image/holdbackgroundimage.h" +#include "../vtools/undocommands/image/renamebackgroundimage.h" +#include "../vtools/undocommands/image/hidebackgroundimage.h" +#include "../vtools/undocommands/image/hideallbackgroundimages.h" +#include "../vtools/undocommands/image/holdallbackgroundimages.h" +#include "../vtools/undocommands/image/zvaluemovebackgroundimage.h" +#include "../vtools/undocommands/image/movebackgroundimage.h" +#include "../vtools/undocommands/image/rotatebackgroundimage.h" +#include "../vtools/undocommands/image/scalebackgroundimage.h" +#include "../vtools/undocommands/image/resetbackgroundimage.h" +#include "../vmisc/vabstractapplication.h" + +#include +#include + +namespace +{ +enum ImageData +{ + Hold = 0, + Visibility = 1, + Name = 2 +}; + +//--------------------------------------------------------------------------------------------------------------------- +void SetImageHold(QTableWidgetItem *item, const VBackgroundPatternImage &image) +{ + if (item) + { + (image.Hold()) ? item->setIcon(QIcon(QStringLiteral("://icon/16x16/hold_image.png"))) + : item->setIcon(QIcon(QStringLiteral("://icon/16x16/not_hold_image.png"))); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void SetImageVisibility(QTableWidgetItem *item, const VBackgroundPatternImage &image) +{ + if (item) + { + (image.Visible()) ? item->setIcon(QIcon(QStringLiteral("://icon/16x16/open_eye.png"))) + : item->setIcon(QIcon(QStringLiteral("://icon/16x16/closed_eye.png"))); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void SetImageName(QTableWidgetItem *item, const VBackgroundPatternImage &image, const QString &def) +{ + QString imageName = def; + if (not image.Name().isEmpty()) + { + imageName = image.Name(); + } + item->setText(imageName); + item->setToolTip(imageName); +} + +//--------------------------------------------------------------------------------------------------------------------- +void SetCheckBoxValue(QCheckBox *checkbox, bool value) +{ + checkbox->blockSignals(true); + checkbox->setChecked(value); + checkbox->blockSignals(false); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto ScaleUnitConvertor(qreal base, qreal value, ScaleUnit from, ScaleUnit to) -> qreal +{ + auto FromPxTo = [base, to](qreal value) + { + switch (to) + { + case ScaleUnit::Mm: + return (value / PrintDPI) * 25.4; + case ScaleUnit::Cm: + return ((value / PrintDPI) * 25.4) / 10.0; + case ScaleUnit::Inch: + return value / PrintDPI; + case ScaleUnit::Px: + return value; + case ScaleUnit::Percent: + if (qFuzzyIsNull(base)) + { + return 0.0; + } + return value / base * 100.; + default: + break; + } + + return 0.0; + }; + + switch (from) + { + case ScaleUnit::Percent: + return FromPxTo(base * (value / 100.)); + case ScaleUnit::Px: + return FromPxTo(value); + case ScaleUnit::Mm: + return FromPxTo((value / 25.4) * PrintDPI); + case ScaleUnit::Cm: + return FromPxTo(((value * 10.0) / 25.4) * PrintDPI); + case ScaleUnit::Inch: + return FromPxTo(value * PrintDPI); + default: + break; + } + + return 0; +} +} // namespace + +//--------------------------------------------------------------------------------------------------------------------- +VWidgetBackgroundImages::VWidgetBackgroundImages(VAbstractPattern *doc, QWidget *parent) + : QWidget(parent), + ui(new Ui::VWidgetBackgroundImages), + m_doc(doc) +{ + ui->setupUi(this); + + SCASSERT(doc != nullptr) + + UpdateImages(); + + ui->tableWidget->setContextMenuPolicy(Qt::CustomContextMenu); + + connect(doc, &VAbstractPattern::BackgroundImageHoldChanged, this, &VWidgetBackgroundImages::UpdateImage); + connect(doc, &VAbstractPattern::BackgroundImageVisibilityChanged, this, &VWidgetBackgroundImages::UpdateImage); + connect(doc, &VAbstractPattern::BackgroundImageNameChanged, this, &VWidgetBackgroundImages::UpdateImage); + connect(doc, &VAbstractPattern::BackgroundImagesHoldChanged, this, &VWidgetBackgroundImages::UpdateImages); + connect(doc, &VAbstractPattern::BackgroundImagesVisibilityChanged, this, &VWidgetBackgroundImages::UpdateImages); + connect(doc, &VAbstractPattern::BackgroundImagePositionChanged, this, + &VWidgetBackgroundImages::ImagePositionChanged); + connect(doc, &VAbstractPattern::BackgroundImageTransformationChanged, this, + &VWidgetBackgroundImages::ImagePositionChanged); + + connect(ui->tableWidget, &QTableWidget::cellClicked, this, &VWidgetBackgroundImages::ImageHoldChanged); + connect(ui->tableWidget, &QTableWidget::cellClicked, this, &VWidgetBackgroundImages::ImageVisibilityChanged); + connect(ui->tableWidget, &QTableWidget::cellChanged, this, &VWidgetBackgroundImages::ImageNameChanged); + connect(ui->tableWidget, &QTableWidget::customContextMenuRequested, this, &VWidgetBackgroundImages::ContextMenu); + connect(ui->tableWidget, &QTableWidget::currentCellChanged, this, &VWidgetBackgroundImages::CurrentImageChanged); + + connect(ui->toolButtonTop, &QToolButton::clicked, this, &VWidgetBackgroundImages::MoveImageOnTop); + connect(ui->toolButtonUp, &QToolButton::clicked, this, &VWidgetBackgroundImages::MoveImageUp); + connect(ui->toolButtonDown, &QToolButton::clicked, this, &VWidgetBackgroundImages::MoveImageDown); + connect(ui->toolButtonBottom, &QToolButton::clicked, this, &VWidgetBackgroundImages::MoveImageBottom); + + InitImageTranslation(); +} + +//--------------------------------------------------------------------------------------------------------------------- +VWidgetBackgroundImages::~VWidgetBackgroundImages() +{ + delete ui; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VWidgetBackgroundImages::UpdateImages() +{ + FillTable(m_doc->GetBackgroundImages()); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VWidgetBackgroundImages::UpdateImage(const QUuid &id) +{ + int row = ImageRow(id); + if (row == -1) + { + return; + } + + VBackgroundPatternImage image = m_doc->GetBackgroundImage(id); + if (image.IsNull()) + { + return; + } + + ui->tableWidget->blockSignals(true); + + QTableWidgetItem *item = ui->tableWidget->item(row, ImageData::Hold); + SetImageHold(item, image); + + item = ui->tableWidget->item(row, ImageData::Visibility); + SetImageVisibility(item, image); + + item = ui->tableWidget->item(row, ImageData::Name); + SetImageName(item, image, tr("Background image")); + + ui->tableWidget->blockSignals(false); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VWidgetBackgroundImages::ImageSelected(const QUuid &id) +{ + int row = ImageRow(id); + + ui->tableWidget->blockSignals(true); + ui->tableWidget->setCurrentCell(row, ImageData::Name); + ui->tableWidget->blockSignals(false); + + if (row != -1 && not ui->checkBoxRelativeTranslation->isChecked()) + { + SetAbsolutePisition(id); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VWidgetBackgroundImages::ImageHoldChanged(int row, int column) +{ + if (column != ImageData::Hold) + { + return; + } + + QTableWidgetItem *item = ui->tableWidget->item(row, column); + if (item != nullptr) + { + ToggleImageHold(item->data(Qt::UserRole).toUuid()); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VWidgetBackgroundImages::ImageVisibilityChanged(int row, int column) +{ + if (column != ImageData::Visibility) + { + return; + } + + QTableWidgetItem *item = ui->tableWidget->item(row, column); + if (item != nullptr) + { + ToggleImageVisibility(item->data(Qt::UserRole).toUuid()); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VWidgetBackgroundImages::ImageNameChanged(int row, int column) +{ + if (column != ImageData::Name) + { + return; + } + + QTableWidgetItem *item = ui->tableWidget->item(row, column); + if (item != nullptr) + { + auto *command = new RenameBackgroundImage(item->data(Qt::UserRole).toUuid(), item->text(), m_doc); + VAbstractApplication::VApp()->getUndoStack()->push(command); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VWidgetBackgroundImages::ContextMenu(const QPoint &pos) +{ + QTableWidgetItem *item = ui->tableWidget->itemAt(pos); + if(item == nullptr) + { + return; + } + + const int row = item->row(); + item = ui->tableWidget->item(row, 0); + const QUuid id = item->data(Qt::UserRole).toUuid(); + VBackgroundPatternImage image = m_doc->GetBackgroundImage(id); + if (image.IsNull()) + { + return; + } + + auto MultipleChangeHoldTo = [this](bool visibility) + { + for (int r = 0; r < ui->tableWidget->rowCount(); ++r) + { + QTableWidgetItem *rowItem = ui->tableWidget->item(r, ImageData::Visibility); + if (rowItem && visibility != m_doc->GetBackgroundImage(rowItem->data(Qt::UserRole).toUuid()).Hold()) + { + return true; + } + } + + return false; + }; + + auto MultipleChangeVisibilityTo = [this](bool visibility) + { + for (int r = 0; r < ui->tableWidget->rowCount(); ++r) + { + QTableWidgetItem *rowItem = ui->tableWidget->item(r, ImageData::Visibility); + if (rowItem && visibility != m_doc->GetBackgroundImage(rowItem->data(Qt::UserRole).toUuid()).Visible()) + { + return true; + } + } + + return false; + }; + + QMenu menu; + + QAction *holdOption = menu.addAction(tr("Hold")); + holdOption->setCheckable(true); + holdOption->setChecked(image.Hold()); + + QAction *actionVisible = menu.addAction(tr("Visible")); + actionVisible->setCheckable(true); + actionVisible->setChecked(image.Visible()); + + QAction *actionReset = menu.addAction(tr("Reset transformation")); + actionReset->setEnabled(not image.Hold()); + + QAction *actionDelete = menu.addAction(QIcon::fromTheme(editDeleteIcon), tr("Delete")); + + menu.addSeparator(); + QAction *actionHoldAll = menu.addAction(tr("Hold All")); + actionHoldAll->setEnabled(MultipleChangeHoldTo(true)); + QAction *actionUnholdAll = menu.addAction(tr("Unhold All")); + actionUnholdAll->setEnabled(MultipleChangeHoldTo(false)); + + menu.addSeparator(); + QAction *actionHideAll = menu.addAction(tr("Hide All")); + actionHideAll->setEnabled(MultipleChangeVisibilityTo(false)); + QAction *actionShowAll = menu.addAction(tr("Show All")); + actionShowAll->setEnabled(MultipleChangeVisibilityTo(true)); + + QAction *selectedAction = menu.exec(ui->tableWidget->viewport()->mapToGlobal(pos)); + + if (selectedAction == holdOption) + { + ToggleImageHold(id); + } + else if (selectedAction == actionVisible) + { + ToggleImageVisibility(id); + } + else if (selectedAction == actionReset) + { + VAbstractApplication::VApp()->getUndoStack()->push(new ResetBackgroundImage(image.Id(), m_doc)); + } + else if (selectedAction == actionDelete) + { + emit DeleteImage(id); + } + else if (selectedAction == actionHoldAll) + { + auto *command = new HoldAllBackgroundImages(true, m_doc); + VAbstractApplication::VApp()->getUndoStack()->push(command); + } + else if (selectedAction == actionUnholdAll) + { + auto *command = new HoldAllBackgroundImages(false, m_doc); + VAbstractApplication::VApp()->getUndoStack()->push(command); + } + else if (selectedAction == actionHideAll) + { + auto *command = new HideAllBackgroundImages(true, m_doc); + VAbstractApplication::VApp()->getUndoStack()->push(command); + } + else if (selectedAction == actionShowAll) + { + auto *command = new HideAllBackgroundImages(false, m_doc); + VAbstractApplication::VApp()->getUndoStack()->push(command); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VWidgetBackgroundImages::CurrentImageChanged(int currentRow, int currentColumn, int previousRow, int previousColumn) +{ + Q_UNUSED(currentColumn) + Q_UNUSED(previousColumn) + if (previousRow != currentRow) + { + QTableWidgetItem *item = ui->tableWidget->item(currentRow, 0); + if (item != nullptr) + { + emit SelectImage(item->data(Qt::UserRole).toUuid()); + } + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VWidgetBackgroundImages::MoveImageOnTop() +{ + int row = ui->tableWidget->currentRow(); + if (row == -1) + { + return; + } + + QTableWidgetItem *item = ui->tableWidget->item(row, 0); + if (item != nullptr) + { + QUuid id = item->data(Qt::UserRole).toUuid(); + auto *command = new ZValueMoveBackgroundImage(id, ZValueMove::Top, m_doc); + VAbstractApplication::VApp()->getUndoStack()->push(command); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VWidgetBackgroundImages::MoveImageUp() +{ + int row = ui->tableWidget->currentRow(); + if (row == -1) + { + return; + } + + QTableWidgetItem *item = ui->tableWidget->item(row, 0); + if (item != nullptr) + { + QUuid id = item->data(Qt::UserRole).toUuid(); + auto *command = new ZValueMoveBackgroundImage(id, ZValueMove::Up, m_doc); + VAbstractApplication::VApp()->getUndoStack()->push(command); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VWidgetBackgroundImages::MoveImageDown() +{ + int row = ui->tableWidget->currentRow(); + if (row == -1) + { + return; + } + + QTableWidgetItem *item = ui->tableWidget->item(row, 0); + if (item != nullptr) + { + QUuid id = item->data(Qt::UserRole).toUuid(); + auto *command = new ZValueMoveBackgroundImage(id, ZValueMove::Down, m_doc); + VAbstractApplication::VApp()->getUndoStack()->push(command); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VWidgetBackgroundImages::MoveImageBottom() +{ + int row = ui->tableWidget->currentRow(); + if (row == -1) + { + return; + } + + QTableWidgetItem *item = ui->tableWidget->item(row, 0); + if (item != nullptr) + { + QUuid id = item->data(Qt::UserRole).toUuid(); + auto *command = new ZValueMoveBackgroundImage(id, ZValueMove::Bottom, m_doc); + VAbstractApplication::VApp()->getUndoStack()->push(command); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VWidgetBackgroundImages::ApplyImageTransformation() +{ + int row = ui->tableWidget->currentRow(); + if (row == -1) + { + return; + } + + QTableWidgetItem *item = ui->tableWidget->item(row, 0); + if (item == nullptr) + { + return; + } + + QUuid id = item->data(Qt::UserRole).toUuid(); + VBackgroundPatternImage image = m_doc->GetBackgroundImage(id); + + const int index = ui->tabWidgetImageTransformation->currentIndex(); + if (ui->tabWidgetImageTransformation->indexOf(ui->tabTranslate) == index) + { // translate + qreal dx = UnitConvertor(ui->doubleSpinBoxImageHorizontalTranslate->value(), CurrentTranslateUnit(), Unit::Px); + qreal dy = UnitConvertor(ui->doubleSpinBoxImageVerticalTranslate->value(), CurrentTranslateUnit(), Unit::Px); + + if (not ui->checkBoxRelativeTranslation->isChecked()) + { + QRectF rect = image.BoundingRect(); + dx = dx - rect.topLeft().x(); + dy = dy - rect.topLeft().y(); + } + + auto *command = new MoveBackgroundImage(id, dx, dy, m_doc); + VAbstractApplication::VApp()->getUndoStack()->push(command); + } + else if (ui->tabWidgetImageTransformation->indexOf(ui->tabScale) == index) + { // scale + qreal sx = WidthScaleUnitConvertor(ui->doubleSpinBoxScaleWidth->value(), CurrentScaleUnit(), + ScaleUnit::Percent) / 100; + qreal sy = HeightScaleUnitConvertor(ui->doubleSpinBoxScaleHeight->value(), CurrentScaleUnit(), + ScaleUnit::Percent) / 100; + + QTransform imageMatrix = image.Matrix(); + QPointF originPos = image.BoundingRect().center(); + + QTransform m; + m.translate(originPos.x(), originPos.y()); + m.scale(sx, sy); + m.translate(-originPos.x(), -originPos.y()); + imageMatrix *= m; + + auto *command = new ScaleBackgroundImage(id, imageMatrix, m_doc); + VAbstractApplication::VApp()->getUndoStack()->push(command); + + } + else if (ui->tabWidgetImageTransformation->indexOf(ui->tabRotate) == index) + { // rotate + qreal angle = ui->doubleSpinBoxRotationAngle->value(); + + if (ui->toolButtonImageRotationClockwise->isChecked()) + { + angle *= -1; + } + + QTransform imageMatrix = image.Matrix(); + + QPointF originPos = 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(id, imageMatrix, m_doc); + VAbstractApplication::VApp()->getUndoStack()->push(command); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VWidgetBackgroundImages::ResetImageTransformationSettings() +{ + const int index = ui->tabWidgetImageTransformation->currentIndex(); + if (ui->tabWidgetImageTransformation->indexOf(ui->tabTranslate) == index) + { // translate + if (ui->checkBoxRelativeTranslation->isChecked()) + { + ui->doubleSpinBoxImageHorizontalTranslate->setValue(0); + ui->doubleSpinBoxImageVerticalTranslate->setValue(0); + } + else + { + if (ui->tableWidget->currentRow() == -1) + { + ui->doubleSpinBoxImageHorizontalTranslate->setValue(0); + ui->doubleSpinBoxImageVerticalTranslate->setValue(0); + } + } + + int unitIndex = ui->comboBoxTranslateUnit->findData(QVariant(static_cast(Unit::Px))); + if (unitIndex != -1) + { + ui->comboBoxTranslateUnit->setCurrentIndex(unitIndex); + } + } + else if (ui->tabWidgetImageTransformation->indexOf(ui->tabScale) == index) + { // scale + int unitIndex = ui->comboBoxScaleUnit->findData(QVariant(static_cast(ScaleUnit::Percent))); + if (unitIndex != -1) + { + ui->comboBoxScaleUnit->setCurrentIndex(unitIndex); + } + + ui->doubleSpinBoxScaleHeight->setValue(100); + ui->doubleSpinBoxScaleWidth->setValue(100); + } + else if (ui->tabWidgetImageTransformation->indexOf(ui->tabRotate) == index) + { // rotate + ui->doubleSpinBoxRotationAngle->setValue(0); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VWidgetBackgroundImages::RelativeTranslationChanged(bool checked) +{ + if (checked) + { + ui->doubleSpinBoxImageHorizontalTranslate->setValue(0); + ui->doubleSpinBoxImageVerticalTranslate->setValue(0); + } + else + { + int row = ui->tableWidget->currentRow(); + if (row == -1) + { + return; + } + + QTableWidgetItem *item = ui->tableWidget->item(row, 0); + if (item != nullptr) + { + QUuid id = item->data(Qt::UserRole).toUuid(); + SetAbsolutePisition(id); + } + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VWidgetBackgroundImages::ScaleProportionallyChanged(bool checked) +{ + if (checked) + { + qreal value = ui->doubleSpinBoxScaleWidth->value(); + ui->doubleSpinBoxScaleHeight->setValue(value); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VWidgetBackgroundImages::ScaleWidthChanged(double value) +{ + if (ui->checkBoxScaleProportionally->isChecked()) + { + ScaleUnit unit = CurrentScaleUnit(); + if (unit == ScaleUnit::Percent) + { + ui->doubleSpinBoxScaleHeight->blockSignals(true); + ui->doubleSpinBoxScaleHeight->setValue(value); + ui->doubleSpinBoxScaleHeight->blockSignals(false); + } + else + { + qreal factor = WidthScaleUnitConvertor(value, unit, ScaleUnit::Percent) / 100.; + qreal heightPx = ImageHeight() * factor; + qreal height = HeightScaleUnitConvertor(heightPx, ScaleUnit::Px, unit); + + ui->doubleSpinBoxScaleHeight->blockSignals(true); + ui->doubleSpinBoxScaleHeight->setValue(height); + ui->doubleSpinBoxScaleHeight->blockSignals(false); + } + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VWidgetBackgroundImages::ScaleHeightChanged(double value) +{ + if (ui->checkBoxScaleProportionally->isChecked()) + { + ScaleUnit unit = CurrentScaleUnit(); + if (unit == ScaleUnit::Percent) + { + ui->doubleSpinBoxScaleWidth->blockSignals(true); + ui->doubleSpinBoxScaleWidth->setValue(value); + ui->doubleSpinBoxScaleWidth->blockSignals(false); + } + else + { + qreal factor = HeightScaleUnitConvertor(value, unit, ScaleUnit::Percent) / 100.; + qreal widthPx = ImageWidth() * factor; + qreal width = WidthScaleUnitConvertor(widthPx, ScaleUnit::Px, unit); + + ui->doubleSpinBoxScaleHeight->blockSignals(true); + ui->doubleSpinBoxScaleHeight->setValue(width); + ui->doubleSpinBoxScaleHeight->blockSignals(false); + } + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VWidgetBackgroundImages::ImagePositionChanged(const QUuid &id) +{ + if (ui->checkBoxRelativeTranslation->isChecked()) + { + return; + } + + int row = ui->tableWidget->currentRow(); + if (row == -1) + { + return; + } + + QTableWidgetItem *item = ui->tableWidget->item(row, 0); + if (item != nullptr) + { + QUuid curentId = item->data(Qt::UserRole).toUuid(); + if (curentId != id) + { + return; + } + + SetAbsolutePisition(id); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VWidgetBackgroundImages::FillTable(const QVector &images) +{ + ui->tableWidget->blockSignals(true); + ui->tableWidget->clear(); + + ui->tableWidget->setColumnCount(3); + ui->tableWidget->setRowCount(images.size()); + qint32 currentRow = -1; + + auto ReadOnly = [](QTableWidgetItem *item) + { + // set the item non-editable (view only), and non-selectable + Qt::ItemFlags flags = item->flags(); + flags &= ~(Qt::ItemIsEditable); // reset/clear the flag + item->setFlags(flags); + }; + + for (const auto &image : images) + { + ++currentRow; + + // Hold + auto *item = new QTableWidgetItem(); + item->setTextAlignment(Qt::AlignHCenter); + SetImageHold(item, image); + item->setData(Qt::UserRole, image.Id()); + ReadOnly(item); + ui->tableWidget->setItem(currentRow, 0, item); + + // Visibility + item = new QTableWidgetItem(); + item->setTextAlignment(Qt::AlignHCenter); + SetImageVisibility(item, image); + item->setData(Qt::UserRole, image.Id()); + ReadOnly(item); + ui->tableWidget->setItem(currentRow, 1, item); + + item = new QTableWidgetItem(); + item->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter); + item->setData(Qt::UserRole, image.Id()); + SetImageName(item, image, tr("Background image")); + ui->tableWidget->setItem(currentRow, 2, item); + } + + ui->tableWidget->resizeColumnsToContents(); + ui->tableWidget->resizeRowsToContents(); + ui->tableWidget->blockSignals(false); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VWidgetBackgroundImages::ToggleImageHold(const QUuid &id) const +{ + VBackgroundPatternImage image = m_doc->GetBackgroundImage(id); + if (not image.IsNull()) + { + auto *command = new HoldBackgroundImage(image.Id(), not image.Hold(), m_doc); + VAbstractApplication::VApp()->getUndoStack()->push(command); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VWidgetBackgroundImages::ToggleImageVisibility(const QUuid &id) const +{ + VBackgroundPatternImage image = m_doc->GetBackgroundImage(id); + if (not image.IsNull()) + { + auto *command = new HideBackgroundImage(image.Id(), image.Visible(), m_doc); + VAbstractApplication::VApp()->getUndoStack()->push(command); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VWidgetBackgroundImages::ImageRow(const QUuid &id) const -> int +{ + for (int r = 0; r < ui->tableWidget->rowCount(); ++r) + { + QTableWidgetItem *item = ui->tableWidget->item(r, 0); + if (item != nullptr && id == item->data(Qt::UserRole).toUuid()) + { + return r; + } + } + + return -1; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VWidgetBackgroundImages::CurrentTranslateUnit() const -> Unit +{ + return static_cast(ui->comboBoxTranslateUnit->currentData().toInt()); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VWidgetBackgroundImages::CurrentScaleUnit() const -> enum ScaleUnit +{ + return static_cast(ui->comboBoxScaleUnit->currentData().toInt()); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VWidgetBackgroundImages::InitImageTranslation() +{ + // Translate + ui->comboBoxTranslateUnit->addItem(tr("Pixels"), QVariant(static_cast(Unit::Px))); + ui->comboBoxTranslateUnit->addItem(tr("Millimiters"), QVariant(static_cast(Unit::Mm))); + ui->comboBoxTranslateUnit->addItem(tr("Centimeters"), QVariant(static_cast(Unit::Cm))); + ui->comboBoxTranslateUnit->addItem(tr("Inches"), QVariant(static_cast(Unit::Inch))); + + ui->comboBoxTranslateUnit->blockSignals(true); + ui->comboBoxTranslateUnit->setCurrentIndex(0); + ui->comboBoxTranslateUnit->blockSignals(false); + + const int minTranslate = -10000; + const int maxTranslate = 10000; + + ui->doubleSpinBoxImageHorizontalTranslate->setMinimum( + UnitConvertor(minTranslate, Unit::Cm, m_oldImageTranslationUnit)); + ui->doubleSpinBoxImageHorizontalTranslate->setMaximum( + UnitConvertor(maxTranslate, Unit::Cm, m_oldImageTranslationUnit)); + ui->doubleSpinBoxImageHorizontalTranslate->setValue(0); + + ui->doubleSpinBoxImageVerticalTranslate->setMinimum( + UnitConvertor(minTranslate, Unit::Cm, m_oldImageTranslationUnit)); + ui->doubleSpinBoxImageVerticalTranslate->setMaximum( + UnitConvertor(maxTranslate, Unit::Cm, m_oldImageTranslationUnit)); + ui->doubleSpinBoxImageVerticalTranslate->setValue(0); + + connect(ui->comboBoxTranslateUnit, QOverload::of(&QComboBox::currentIndexChanged), this, + [this, minTranslate, maxTranslate]() + { + const Unit newUnit = CurrentTranslateUnit(); + const qreal oldTranslateX = ui->doubleSpinBoxImageHorizontalTranslate->value(); + const qreal oldTranslateY = ui->doubleSpinBoxImageVerticalTranslate->value(); + + ui->doubleSpinBoxImageHorizontalTranslate->setMinimum(UnitConvertor(minTranslate, Unit::Cm, newUnit)); + ui->doubleSpinBoxImageHorizontalTranslate->setMaximum(UnitConvertor(maxTranslate, Unit::Cm, newUnit)); + + ui->doubleSpinBoxImageVerticalTranslate->setMinimum(UnitConvertor(minTranslate, Unit::Cm, newUnit)); + ui->doubleSpinBoxImageVerticalTranslate->setMaximum(UnitConvertor(maxTranslate, Unit::Cm, newUnit)); + + ui->doubleSpinBoxImageHorizontalTranslate->setValue( + UnitConvertor(oldTranslateX, m_oldImageTranslationUnit, newUnit)); + ui->doubleSpinBoxImageVerticalTranslate->setValue( + UnitConvertor(oldTranslateY, m_oldImageTranslationUnit, newUnit)); + + m_oldImageTranslationUnit = newUnit; + }); + + SetCheckBoxValue(ui->checkBoxRelativeTranslation, true); + connect(ui->checkBoxRelativeTranslation, &QCheckBox::toggled, this, + &VWidgetBackgroundImages::RelativeTranslationChanged); + + // Scale + ui->comboBoxScaleUnit->addItem(QChar('%'), QVariant(static_cast(ScaleUnit::Percent))); + ui->comboBoxScaleUnit->addItem(tr("Millimiters"), QVariant(static_cast(ScaleUnit::Mm))); + ui->comboBoxScaleUnit->addItem(tr("Centimeters"), QVariant(static_cast(ScaleUnit::Cm))); + ui->comboBoxScaleUnit->addItem(tr("Inches"), QVariant(static_cast(ScaleUnit::Inch))); + ui->comboBoxScaleUnit->addItem(tr("Pixels"), QVariant(static_cast(ScaleUnit::Px))); + + ui->comboBoxScaleUnit->blockSignals(true); + ui->comboBoxScaleUnit->setCurrentIndex(0); + ui->comboBoxScaleUnit->blockSignals(false); + + const int minScale = -100000; + const int maxScale = 100000; + + ui->doubleSpinBoxScaleWidth->setMinimum(minScale); + ui->doubleSpinBoxScaleWidth->setMaximum(maxScale); + ui->doubleSpinBoxScaleWidth->setValue(100); + + ui->doubleSpinBoxScaleHeight->setMinimum(minScale); + ui->doubleSpinBoxScaleHeight->setMaximum(maxScale); + ui->doubleSpinBoxScaleHeight->setValue(100); + + connect(ui->comboBoxScaleUnit, QOverload::of(&QComboBox::currentIndexChanged), this, + [this, minScale, maxScale]() + { + const enum ScaleUnit newUnit = CurrentScaleUnit(); + const qreal oldScaleWidth = ui->doubleSpinBoxScaleWidth->value(); + const qreal oldScaleHeight = ui->doubleSpinBoxScaleHeight->value(); + + ui->doubleSpinBoxScaleWidth->blockSignals(true); + + ui->doubleSpinBoxScaleWidth->setMinimum(WidthScaleUnitConvertor(minScale, ScaleUnit::Percent, newUnit)); + ui->doubleSpinBoxScaleWidth->setMinimum(WidthScaleUnitConvertor(minScale, ScaleUnit::Percent, newUnit)); + + ui->doubleSpinBoxScaleWidth->setValue( + WidthScaleUnitConvertor(oldScaleWidth, m_oldImageScaleUnit, newUnit)); + ui->doubleSpinBoxScaleWidth->blockSignals(false); + + ui->doubleSpinBoxScaleHeight->blockSignals(true); + + ui->doubleSpinBoxScaleHeight->setMaximum(HeightScaleUnitConvertor(maxScale, ScaleUnit::Percent, newUnit)); + ui->doubleSpinBoxScaleHeight->setMaximum(HeightScaleUnitConvertor(maxScale, ScaleUnit::Percent, newUnit)); + + if (ui->checkBoxScaleProportionally->isChecked() && newUnit == ScaleUnit::Percent) + { + ui->doubleSpinBoxScaleHeight->setValue(ui->doubleSpinBoxScaleWidth->value()); + } + else + { + ui->doubleSpinBoxScaleHeight->setValue( + HeightScaleUnitConvertor(oldScaleHeight, m_oldImageScaleUnit, newUnit)); + } + ui->doubleSpinBoxScaleHeight->blockSignals(false); + + m_oldImageScaleUnit = newUnit; + }); + + connect(ui->doubleSpinBoxScaleHeight, QOverload::of(&QDoubleSpinBox::valueChanged), this, + &VWidgetBackgroundImages::ScaleHeightChanged); + connect(ui->doubleSpinBoxScaleWidth, QOverload::of(&QDoubleSpinBox::valueChanged), this, + &VWidgetBackgroundImages::ScaleWidthChanged); + + SetCheckBoxValue(ui->checkBoxScaleProportionally, true); + connect(ui->checkBoxScaleProportionally, &QCheckBox::toggled, this, + &VWidgetBackgroundImages::ScaleProportionallyChanged); + + // Rotate + ui->doubleSpinBoxRotationAngle->setValue(0); + + ui->toolButtonImageRotationAnticlockwise->setChecked(true); + + QPushButton *bApply = ui->buttonBox->button(QDialogButtonBox::Apply); + SCASSERT(bApply != nullptr) + connect(bApply, &QPushButton::clicked, this, &VWidgetBackgroundImages::ApplyImageTransformation); + + QPushButton *bReset = ui->buttonBox->button(QDialogButtonBox::Reset); + SCASSERT(bReset != nullptr) + connect(bReset, &QPushButton::clicked, this, &VWidgetBackgroundImages::ResetImageTransformationSettings); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VWidgetBackgroundImages::ImageWidth() const -> qreal +{ + qreal width = 0; + + int row = ui->tableWidget->currentRow(); + if (row != -1) + { + QTableWidgetItem *item = ui->tableWidget->item(row, 0); + if (item != nullptr) + { + QUuid id = item->data(Qt::UserRole).toUuid(); + VBackgroundPatternImage image = m_doc->GetBackgroundImage(id); + width = image.Size().width(); + } + } + + return width; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VWidgetBackgroundImages::ImageHeight() const -> qreal +{ + qreal height = 0; + + int row = ui->tableWidget->currentRow(); + if (row != -1) + { + QTableWidgetItem *item = ui->tableWidget->item(row, 0); + if (item != nullptr) + { + QUuid id = item->data(Qt::UserRole).toUuid(); + VBackgroundPatternImage image = m_doc->GetBackgroundImage(id); + height = image.Size().height(); + } + } + + return height; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VWidgetBackgroundImages::WidthScaleUnitConvertor(qreal value, ScaleUnit from, ScaleUnit to) const -> qreal +{ + return ScaleUnitConvertor(ImageWidth(), value, from, to); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VWidgetBackgroundImages::HeightScaleUnitConvertor(qreal value, ScaleUnit from, ScaleUnit to) const -> qreal +{ + return ScaleUnitConvertor(ImageHeight(), value, from, to); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VWidgetBackgroundImages::SetAbsolutePisition(const QUuid &id) +{ + VBackgroundPatternImage image = m_doc->GetBackgroundImage(id); + QRectF rect = image.BoundingRect(); + + ui->doubleSpinBoxImageHorizontalTranslate->setValue( + UnitConvertor(rect.topLeft().x(), Unit::Px, CurrentTranslateUnit())); + ui->doubleSpinBoxImageVerticalTranslate->setValue( + UnitConvertor(rect.topLeft().y(), Unit::Px, CurrentTranslateUnit())); +} diff --git a/src/app/valentina/dialogs/vwidgetbackgroundimages.h b/src/app/valentina/dialogs/vwidgetbackgroundimages.h new file mode 100644 index 000000000..c89955495 --- /dev/null +++ b/src/app/valentina/dialogs/vwidgetbackgroundimages.h @@ -0,0 +1,112 @@ +/************************************************************************ + ** + ** @file vwidgetbackgroundimages.h + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ +#ifndef VWIDGETBACKGROUNDIMAGES_H +#define VWIDGETBACKGROUNDIMAGES_H + +#include + +#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 &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 diff --git a/src/app/valentina/dialogs/vwidgetbackgroundimages.ui b/src/app/valentina/dialogs/vwidgetbackgroundimages.ui new file mode 100644 index 000000000..bf531036a --- /dev/null +++ b/src/app/valentina/dialogs/vwidgetbackgroundimages.ui @@ -0,0 +1,418 @@ + + + VWidgetBackgroundImages + + + + 0 + 0 + 401 + 640 + + + + Form + + + + + + true + + + + + 0 + 0 + 381 + 620 + + + + + + + + 0 + 0 + + + + Transformation + + + + + + 0 + + + + Translate + + + + + + + + Horizontal: + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + 0.100000000000000 + + + + + + + + + + Vertical: + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + 0.100000000000000 + + + + + + + + + Relative translation + + + true + + + + + + + + Scale + + + + + + + + Width: + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + 0.100000000000000 + + + + + + + + + + Height: + + + + + + + -10000.000000000000000 + + + 10000.000000000000000 + + + 0.100000000000000 + + + + + + + + + Scale proportionally + + + true + + + + + + + + Rotate + + + + + + Rotation + + + + + + + + + + ../../puzzle../../puzzle + + + true + + + buttonGroup + + + + + + + ° + + + 3 + + + -360.000000000000000 + + + 360.000000000000000 + + + 0.100000000000000 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + ../../puzzle../../puzzle + + + true + + + true + + + buttonGroup + + + + + + + + 0 + 0 + + + + Angle: + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + QDialogButtonBox::Apply|QDialogButtonBox::Reset + + + + + + + + + + Z Value + + + + + + ... + + + + + + + 24 + 24 + + + + + + + + ... + + + + + + + 24 + 24 + + + + + + + + ... + + + + + + + 24 + 24 + + + + + + + + ... + + + + + + + 24 + 24 + + + + + + + + + + + + 1 + 1 + + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + false + + + 16 + + + true + + + false + + + 10 + + + + + + + + + + + + + + + diff --git a/src/app/valentina/mainwindow.cpp b/src/app/valentina/mainwindow.cpp index 8631e090f..52551e5d0 100644 --- a/src/app/valentina/mainwindow.cpp +++ b/src/app/valentina/mainwindow.cpp @@ -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 #include #include +#include +#include #if defined(Q_OS_WIN32) && QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) #include @@ -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(Tool::LAST_ONE_DO_NOT_USE) == 55, "Check if need to extend."); + Q_STATIC_ASSERT_X(static_cast(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(Tool::LAST_ONE_DO_NOT_USE) == 55, "Check if all tools were connected."); + Q_STATIC_ASSERT_X(static_cast(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(Tool::LAST_ONE_DO_NOT_USE) == 55, "Not all tools were handled."); + Q_STATIC_ASSERT_X(static_cast(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(Tool::LAST_ONE_DO_NOT_USE) == 55, "Not all tools were handled."); + Q_STATIC_ASSERT_X(static_cast(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(Tool::LAST_ONE_DO_NOT_USE) == 55, "Not all tools were handled."); + Q_STATIC_ASSERT_X(static_cast(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 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); diff --git a/src/app/valentina/mainwindow.h b/src/app/valentina/mainwindow.h index 17637bcec..d4d8bd533 100644 --- a/src/app/valentina/mainwindow.h +++ b/src/app/valentina/mainwindow.h @@ -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> lock; QList toolButtonPointerList; @@ -308,6 +321,15 @@ private: QTimer *m_gradation; + QMap m_backgroundImages{}; + QMap 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 &control); @@ -422,6 +444,8 @@ private: void StoreDimensions(); void ExportDraw(const QString &fileName); + + void NewBackgroundImageItem(const VBackgroundPatternImage &image); }; #endif // MAINWINDOW_H diff --git a/src/app/valentina/mainwindow.ui b/src/app/valentina/mainwindow.ui index 21deed217..c21a81b6f 100644 --- a/src/app/valentina/mainwindow.ui +++ b/src/app/valentina/mainwindow.ui @@ -1613,7 +1613,7 @@ 0 0 140 - 168 + 169 @@ -1778,6 +1778,8 @@ + + @@ -2185,6 +2187,15 @@ + + + Background images + + + 2 + + + @@ -3094,6 +3105,14 @@ Shop + + + false + + + Add background image + + diff --git a/src/app/valentina/mainwindowsnogui.h b/src/app/valentina/mainwindowsnogui.h index 0e43a8ba0..c793df64d 100644 --- a/src/app/valentina/mainwindowsnogui.h +++ b/src/app/valentina/mainwindowsnogui.h @@ -107,6 +107,7 @@ protected: QAction *redoAction{nullptr}; QAction *actionDockWidgetToolOptions{nullptr}; QAction *actionDockWidgetGroups{nullptr}; + QAction *actionDockWidgetBackgroundImages{nullptr}; bool isNoScaling{false}; bool isNeedAutosave{false}; diff --git a/src/app/valentina/xml/vpattern.cpp b/src/app/valentina/xml/vpattern.cpp index 2c299651d..d21d64849 100644 --- a/src/app/valentina/xml/vpattern.cpp +++ b/src/app/valentina/xml/vpattern.cpp @@ -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(Tool::LAST_ONE_DO_NOT_USE) == 55, "Not all tools were used."); + Q_STATIC_ASSERT_X(static_cast(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; diff --git a/src/libs/ifc/schema/pattern/v0.9.0.xsd b/src/libs/ifc/schema/pattern/v0.9.0.xsd index 2bc8afac8..db88fb7a9 100644 --- a/src/libs/ifc/schema/pattern/v0.9.0.xsd +++ b/src/libs/ifc/schema/pattern/v0.9.0.xsd @@ -59,6 +59,28 @@ + + + + + + + + + + + + + + + + + + + + + + @@ -778,6 +800,10 @@ + + + + @@ -1129,4 +1155,9 @@ + + + + + diff --git a/src/libs/ifc/xml/utils.cpp b/src/libs/ifc/xml/utils.cpp new file mode 100644 index 000000000..9ec56c910 --- /dev/null +++ b/src/libs/ifc/xml/utils.cpp @@ -0,0 +1,110 @@ +/************************************************************************ + ** + ** @file utils.cpp + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ +#include "utils.h" + +#include +#include +#include +#include +#include +#include +#include + +//--------------------------------------------------------------------------------------------------------------------- +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 aliases = mime.aliases().toSet(); + aliases.insert(mime.name()); + + QSet 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 supportedFormats = QImageReader::supportedImageFormats(); + const QSet 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(";;")); +} diff --git a/src/libs/ifc/xml/utils.h b/src/libs/ifc/xml/utils.h new file mode 100644 index 000000000..6c9487158 --- /dev/null +++ b/src/libs/ifc/xml/utils.h @@ -0,0 +1,42 @@ +/************************************************************************ + ** + ** @file utils.h + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ +#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 diff --git a/src/libs/ifc/xml/vabstractpattern.cpp b/src/libs/ifc/xml/vabstractpattern.cpp index c4ce5b1fd..903449644 100644 --- a/src/libs/ifc/xml/vabstractpattern.cpp +++ b/src/libs/ifc/xml/vabstractpattern.cpp @@ -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(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 +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(Tool::LAST_ONE_DO_NOT_USE) == 55, "Check if need to ignore modeling tools."); + Q_STATIC_ASSERT_X(static_cast(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 +{ + QVector 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 &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 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(Tool::LAST_ONE_DO_NOT_USE) == 55); + Q_STATIC_ASSERT(static_cast(Tool::LAST_ONE_DO_NOT_USE) == 59); QVector expressions; const QDomNodeList list = elementsByTagName(TagPoint); @@ -1559,7 +1741,7 @@ QVector 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(Tool::LAST_ONE_DO_NOT_USE) == 55); + Q_STATIC_ASSERT(static_cast(Tool::LAST_ONE_DO_NOT_USE) == 59); QVector expressions; const QDomNodeList list = elementsByTagName(TagArc); @@ -1583,7 +1765,7 @@ QVector 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(Tool::LAST_ONE_DO_NOT_USE) == 55); + Q_STATIC_ASSERT(static_cast(Tool::LAST_ONE_DO_NOT_USE) == 59); QVector expressions; const QDomNodeList list = elementsByTagName(TagElArc); @@ -1616,7 +1798,7 @@ QVector 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(Tool::LAST_ONE_DO_NOT_USE) == 55); + Q_STATIC_ASSERT(static_cast(Tool::LAST_ONE_DO_NOT_USE) == 59); QVector expressions; const QDomNodeList list = elementsByTagName(AttrPathPoint); @@ -1654,7 +1836,7 @@ QVector 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(Tool::LAST_ONE_DO_NOT_USE) == 55); + Q_STATIC_ASSERT(static_cast(Tool::LAST_ONE_DO_NOT_USE) == 59); QVector expressions; const QDomNodeList list = elementsByTagName(TagOperation); @@ -1676,7 +1858,7 @@ QVector 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(Tool::LAST_ONE_DO_NOT_USE) == 55); + Q_STATIC_ASSERT(static_cast(Tool::LAST_ONE_DO_NOT_USE) == 59); QVector expressions; @@ -1700,7 +1882,7 @@ QVector 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(Tool::LAST_ONE_DO_NOT_USE) == 55); + Q_STATIC_ASSERT(static_cast(Tool::LAST_ONE_DO_NOT_USE) == 59); QVector expressions; const QDomNodeList list = elementsByTagName(TagPath); @@ -1738,7 +1920,7 @@ QVector 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(Tool::LAST_ONE_DO_NOT_USE) == 55); + Q_STATIC_ASSERT(static_cast(Tool::LAST_ONE_DO_NOT_USE) == 59); QVector expressions; const QDomNodeList list = elementsByTagName(TagDetail); @@ -1951,6 +2133,96 @@ void VAbstractPattern::SetFMeasurements(QDomElement &element, const QVector 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(element, AttrContentType, image.ContentType(), + [](const QString &contentType) noexcept {return contentType.isEmpty();}); + setTagText(element, image.ContentData()); + SetAttributeOrRemoveIf(element, AttrPath, image.FilePath(), + [](const QString &path) noexcept {return path.isEmpty();}); + } + + SetAttributeOrRemoveIf(element, AttrName, image.Name(), + [](const QString &name) noexcept {return name.isEmpty();}); + SetAttribute(element, AttrTransform, TransformToString(image.Matrix())); + + SetAttributeOrRemoveIf(element, AttrHold, image.Hold(), [](bool hold) noexcept {return not hold;}); + SetAttributeOrRemoveIf(element, AttrZValue, image.ZValue(), [](qreal z) noexcept {return qFuzzyIsNull(z);}); + SetAttributeOrRemoveIf(element, AttrVisible, image.Visible(), [](bool visible) noexcept {return visible;}); +} + //--------------------------------------------------------------------------------------------------------------------- /** * @brief IsModified state of the document for cases that do not cover QUndoStack. diff --git a/src/libs/ifc/xml/vabstractpattern.h b/src/libs/ifc/xml/vabstractpattern.h index 3b28de601..d4a2a9c5d 100644 --- a/src/libs/ifc/xml/vabstractpattern.h +++ b/src/libs/ifc/xml/vabstractpattern.h @@ -39,6 +39,7 @@ #include #include #include +#include #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; + void SaveBackgroundImages(const QVector &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 GetFMeasurements(const QDomElement &element) const; void SetFMeasurements(QDomElement &element, const QVector &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 diff --git a/src/libs/ifc/xml/vbackgroundpatternimage.cpp b/src/libs/ifc/xml/vbackgroundpatternimage.cpp new file mode 100644 index 000000000..c0230363d --- /dev/null +++ b/src/libs/ifc/xml/vbackgroundpatternimage.cpp @@ -0,0 +1,310 @@ +/************************************************************************ + ** + ** @file vbackgroundpatternimage.cpp + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ +#include "vbackgroundpatternimage.h" + +#include "utils.h" + +#include +#include +#include +#include +#include +#include +#include + +//--------------------------------------------------------------------------------------------------------------------- +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 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; +} diff --git a/src/libs/ifc/xml/vbackgroundpatternimage.h b/src/libs/ifc/xml/vbackgroundpatternimage.h new file mode 100644 index 000000000..7f7897965 --- /dev/null +++ b/src/libs/ifc/xml/vbackgroundpatternimage.h @@ -0,0 +1,109 @@ +/************************************************************************ + ** + ** @file vbackgroundpatternimage.h + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ +#ifndef VBACKGROUNDPATTERNIMAGE_H +#define VBACKGROUNDPATTERNIMAGE_H + +#include +#include +#include +#include + +#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 diff --git a/src/libs/ifc/xml/vpatternimage.cpp b/src/libs/ifc/xml/vpatternimage.cpp index d37489af1..6bc21c0ae 100644 --- a/src/libs/ifc/xml/vpatternimage.cpp +++ b/src/libs/ifc/xml/vpatternimage.cpp @@ -39,34 +39,7 @@ #include #include -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 aliases = mime.aliases().toSet(); aliases.insert(mime.name()); - QSet 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)); } //--------------------------------------------------------------------------------------------------------------------- diff --git a/src/libs/ifc/xml/vpatternimage.h b/src/libs/ifc/xml/vpatternimage.h index 615b0bb79..81dced06a 100644 --- a/src/libs/ifc/xml/vpatternimage.h +++ b/src/libs/ifc/xml/vpatternimage.h @@ -31,7 +31,6 @@ #include #include - class QPixmap; class QMimeType; diff --git a/src/libs/ifc/xml/xml.pri b/src/libs/ifc/xml/xml.pri index fa8c2ce4a..c142d3cd4 100644 --- a/src/libs/ifc/xml/xml.pri +++ b/src/libs/ifc/xml/xml.pri @@ -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 \ diff --git a/src/libs/vformat/vpatternrecipe.cpp b/src/libs/vformat/vpatternrecipe.cpp index b6b3adaa3..c38e3f89a 100644 --- a/src/libs/vformat/vpatternrecipe.cpp +++ b/src/libs/vformat/vpatternrecipe.cpp @@ -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(Tool::LAST_ONE_DO_NOT_USE) == 55, "Not all tools were used in history."); + Q_STATIC_ASSERT_X(static_cast(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; diff --git a/src/libs/vmisc/def.h b/src/libs/vmisc/def.h index f15aa1402..89a98fe4a 100644 --- a/src/libs/vmisc/def.h +++ b/src/libs/vmisc/def.h @@ -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 }; diff --git a/src/libs/vmisc/defglobal.h b/src/libs/vmisc/defglobal.h index 5ccdbc213..7479967a1 100644 --- a/src/libs/vmisc/defglobal.h +++ b/src/libs/vmisc/defglobal.h @@ -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 diff --git a/src/libs/vmisc/share/resources/icon.qrc b/src/libs/vmisc/share/resources/icon.qrc index 7e62554aa..da1d88ca5 100644 --- a/src/libs/vmisc/share/resources/icon.qrc +++ b/src/libs/vmisc/share/resources/icon.qrc @@ -94,5 +94,58 @@ icon/24x24/close.png icon/24x24/close@2x.png icon/layout.png + icon/32x32/rotate-top-left-hover@2x.png + icon/32x32/rotate-top-left-hover.png + icon/32x32/rotate-top-left@2x.png + icon/32x32/rotate-top-left.png + icon/32x32/rotate-top-right-hover@2x.png + icon/32x32/rotate-top-right-hover.png + icon/32x32/rotate-top-right@2x.png + icon/32x32/rotate-top-right.png + icon/32x32/rotate-bottom-right-hover@2x.png + icon/32x32/rotate-bottom-right-hover.png + icon/32x32/rotate-bottom-right@2x.png + icon/32x32/rotate-bottom-right.png + icon/32x32/rotate-bottom-left-hover@2x.png + icon/32x32/rotate-bottom-left-hover.png + icon/32x32/rotate-bottom-left@2x.png + icon/32x32/rotate-bottom-left.png + icon/32x32/expand2-hover@2x.png + icon/32x32/expand2-hover.png + icon/32x32/expand2@2x.png + icon/32x32/expand2.png + icon/32x32/expand1-hover@2x.png + icon/32x32/expand1-hover.png + icon/32x32/expand1@2x.png + icon/32x32/expand1.png + icon/32x32/double-arrow-vertical-hover@2x.png + icon/32x32/double-arrow-vertical-hover.png + icon/32x32/double-arrow-vertical@2x.png + icon/32x32/double-arrow-vertical.png + icon/32x32/double-arrow-horizontal-hover@2x.png + icon/32x32/double-arrow-horizontal@2x.png + icon/32x32/double-arrow-horizontal-hover.png + icon/32x32/double-arrow-horizontal.png + icon/svg/broken_path.svg + icon/16x16/not_hold_image@2x.png + icon/16x16/not_hold_image.png + icon/16x16/hold_image@2x.png + icon/16x16/hold_image.png + icon/32x32/rotate-top-right-disabled@2x.png + icon/32x32/rotate-top-right-disabled.png + icon/32x32/rotate-top-left-disabled@2x.png + icon/32x32/rotate-top-left-disabled.png + icon/32x32/rotate-bottom-right-disabled@2x.png + icon/32x32/rotate-bottom-right-disabled.png + icon/32x32/rotate-bottom-left-disabled@2x.png + icon/32x32/rotate-bottom-left-disabled.png + icon/32x32/expand2-disabled@2x.png + icon/32x32/expand2-disabled.png + icon/32x32/expand1-disabled@2x.png + icon/32x32/expand1-disabled.png + icon/32x32/double-arrow-vertical-disabled@2x.png + icon/32x32/double-arrow-vertical-disabled.png + icon/32x32/double-arrow-horizontal-disabled@2x.png + icon/32x32/double-arrow-horizontal-disabled.png diff --git a/src/libs/vmisc/share/resources/icon/16x16/hold_image.png b/src/libs/vmisc/share/resources/icon/16x16/hold_image.png new file mode 100644 index 000000000..5b90c5fb9 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/16x16/hold_image.png differ diff --git a/src/libs/vmisc/share/resources/icon/16x16/hold_image@2x.png b/src/libs/vmisc/share/resources/icon/16x16/hold_image@2x.png new file mode 100644 index 000000000..f4912d48d Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/16x16/hold_image@2x.png differ diff --git a/src/libs/vmisc/share/resources/icon/16x16/not_hold_image.png b/src/libs/vmisc/share/resources/icon/16x16/not_hold_image.png new file mode 100644 index 000000000..3782e02cd Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/16x16/not_hold_image.png differ diff --git a/src/libs/vmisc/share/resources/icon/16x16/not_hold_image@2x.png b/src/libs/vmisc/share/resources/icon/16x16/not_hold_image@2x.png new file mode 100644 index 000000000..8ac0d649f Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/16x16/not_hold_image@2x.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/double-arrow-horizontal-disabled.png b/src/libs/vmisc/share/resources/icon/32x32/double-arrow-horizontal-disabled.png new file mode 100644 index 000000000..c960cf06f Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/double-arrow-horizontal-disabled.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/double-arrow-horizontal-disabled@2x.png b/src/libs/vmisc/share/resources/icon/32x32/double-arrow-horizontal-disabled@2x.png new file mode 100644 index 000000000..3195fbcf0 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/double-arrow-horizontal-disabled@2x.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/double-arrow-horizontal-hover.png b/src/libs/vmisc/share/resources/icon/32x32/double-arrow-horizontal-hover.png new file mode 100644 index 000000000..7f650065f Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/double-arrow-horizontal-hover.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/double-arrow-horizontal-hover@2x.png b/src/libs/vmisc/share/resources/icon/32x32/double-arrow-horizontal-hover@2x.png new file mode 100644 index 000000000..c19c80031 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/double-arrow-horizontal-hover@2x.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/double-arrow-horizontal.png b/src/libs/vmisc/share/resources/icon/32x32/double-arrow-horizontal.png new file mode 100644 index 000000000..579f38c22 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/double-arrow-horizontal.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/double-arrow-horizontal@2x.png b/src/libs/vmisc/share/resources/icon/32x32/double-arrow-horizontal@2x.png new file mode 100644 index 000000000..1aa418fd1 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/double-arrow-horizontal@2x.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/double-arrow-vertical-disabled.png b/src/libs/vmisc/share/resources/icon/32x32/double-arrow-vertical-disabled.png new file mode 100644 index 000000000..15aaa0d7c Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/double-arrow-vertical-disabled.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/double-arrow-vertical-disabled@2x.png b/src/libs/vmisc/share/resources/icon/32x32/double-arrow-vertical-disabled@2x.png new file mode 100644 index 000000000..fc75c19e2 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/double-arrow-vertical-disabled@2x.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/double-arrow-vertical-hover.png b/src/libs/vmisc/share/resources/icon/32x32/double-arrow-vertical-hover.png new file mode 100644 index 000000000..903e8179c Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/double-arrow-vertical-hover.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/double-arrow-vertical-hover@2x.png b/src/libs/vmisc/share/resources/icon/32x32/double-arrow-vertical-hover@2x.png new file mode 100644 index 000000000..17755c2c3 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/double-arrow-vertical-hover@2x.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/double-arrow-vertical.png b/src/libs/vmisc/share/resources/icon/32x32/double-arrow-vertical.png new file mode 100644 index 000000000..8776d89a5 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/double-arrow-vertical.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/double-arrow-vertical@2x.png b/src/libs/vmisc/share/resources/icon/32x32/double-arrow-vertical@2x.png new file mode 100644 index 000000000..8156ab56d Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/double-arrow-vertical@2x.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/expand1-disabled.png b/src/libs/vmisc/share/resources/icon/32x32/expand1-disabled.png new file mode 100644 index 000000000..2113c4925 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/expand1-disabled.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/expand1-disabled@2x.png b/src/libs/vmisc/share/resources/icon/32x32/expand1-disabled@2x.png new file mode 100644 index 000000000..fdf3a1bab Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/expand1-disabled@2x.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/expand1-hover.png b/src/libs/vmisc/share/resources/icon/32x32/expand1-hover.png new file mode 100644 index 000000000..b76843abd Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/expand1-hover.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/expand1-hover@2x.png b/src/libs/vmisc/share/resources/icon/32x32/expand1-hover@2x.png new file mode 100644 index 000000000..f5582f361 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/expand1-hover@2x.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/expand1.png b/src/libs/vmisc/share/resources/icon/32x32/expand1.png new file mode 100644 index 000000000..3af137629 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/expand1.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/expand1@2x.png b/src/libs/vmisc/share/resources/icon/32x32/expand1@2x.png new file mode 100644 index 000000000..c27956626 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/expand1@2x.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/expand2-disabled.png b/src/libs/vmisc/share/resources/icon/32x32/expand2-disabled.png new file mode 100644 index 000000000..2f44074d2 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/expand2-disabled.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/expand2-disabled@2x.png b/src/libs/vmisc/share/resources/icon/32x32/expand2-disabled@2x.png new file mode 100644 index 000000000..8ea6152e1 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/expand2-disabled@2x.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/expand2-hover.png b/src/libs/vmisc/share/resources/icon/32x32/expand2-hover.png new file mode 100644 index 000000000..632180b8b Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/expand2-hover.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/expand2-hover@2x.png b/src/libs/vmisc/share/resources/icon/32x32/expand2-hover@2x.png new file mode 100644 index 000000000..43299180b Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/expand2-hover@2x.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/expand2.png b/src/libs/vmisc/share/resources/icon/32x32/expand2.png new file mode 100644 index 000000000..c09132e5d Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/expand2.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/expand2@2x.png b/src/libs/vmisc/share/resources/icon/32x32/expand2@2x.png new file mode 100644 index 000000000..50087d6d2 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/expand2@2x.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-left-disabled.png b/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-left-disabled.png new file mode 100644 index 000000000..df4cf3d3a Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-left-disabled.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-left-disabled@2x.png b/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-left-disabled@2x.png new file mode 100644 index 000000000..3793c7129 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-left-disabled@2x.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-left-hover.png b/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-left-hover.png new file mode 100644 index 000000000..3bc050adc Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-left-hover.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-left-hover@2x.png b/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-left-hover@2x.png new file mode 100644 index 000000000..41f4161c4 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-left-hover@2x.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-left.png b/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-left.png new file mode 100644 index 000000000..6689d185f Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-left.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-left@2x.png b/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-left@2x.png new file mode 100644 index 000000000..b44f7f2ad Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-left@2x.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-right-disabled.png b/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-right-disabled.png new file mode 100644 index 000000000..236d9919a Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-right-disabled.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-right-disabled@2x.png b/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-right-disabled@2x.png new file mode 100644 index 000000000..deb1b4188 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-right-disabled@2x.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-right-hover.png b/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-right-hover.png new file mode 100644 index 000000000..31e49da46 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-right-hover.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-right-hover@2x.png b/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-right-hover@2x.png new file mode 100644 index 000000000..0db7fd538 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-right-hover@2x.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-right.png b/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-right.png new file mode 100644 index 000000000..a3fa998b4 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-right.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-right@2x.png b/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-right@2x.png new file mode 100644 index 000000000..671a38f99 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/rotate-bottom-right@2x.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/rotate-top-left-disabled.png b/src/libs/vmisc/share/resources/icon/32x32/rotate-top-left-disabled.png new file mode 100644 index 000000000..95b5c2c1a Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/rotate-top-left-disabled.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/rotate-top-left-disabled@2x.png b/src/libs/vmisc/share/resources/icon/32x32/rotate-top-left-disabled@2x.png new file mode 100644 index 000000000..218b30914 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/rotate-top-left-disabled@2x.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/rotate-top-left-hover.png b/src/libs/vmisc/share/resources/icon/32x32/rotate-top-left-hover.png new file mode 100644 index 000000000..e85db7883 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/rotate-top-left-hover.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/rotate-top-left-hover@2x.png b/src/libs/vmisc/share/resources/icon/32x32/rotate-top-left-hover@2x.png new file mode 100644 index 000000000..b14635d5d Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/rotate-top-left-hover@2x.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/rotate-top-left.png b/src/libs/vmisc/share/resources/icon/32x32/rotate-top-left.png new file mode 100644 index 000000000..561c8817a Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/rotate-top-left.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/rotate-top-left@2x.png b/src/libs/vmisc/share/resources/icon/32x32/rotate-top-left@2x.png new file mode 100644 index 000000000..962491024 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/rotate-top-left@2x.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/rotate-top-right-disabled.png b/src/libs/vmisc/share/resources/icon/32x32/rotate-top-right-disabled.png new file mode 100644 index 000000000..b63cdfbc2 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/rotate-top-right-disabled.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/rotate-top-right-disabled@2x.png b/src/libs/vmisc/share/resources/icon/32x32/rotate-top-right-disabled@2x.png new file mode 100644 index 000000000..3f4fd1861 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/rotate-top-right-disabled@2x.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/rotate-top-right-hover.png b/src/libs/vmisc/share/resources/icon/32x32/rotate-top-right-hover.png new file mode 100644 index 000000000..33b1d42a5 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/rotate-top-right-hover.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/rotate-top-right-hover@2x.png b/src/libs/vmisc/share/resources/icon/32x32/rotate-top-right-hover@2x.png new file mode 100644 index 000000000..754361260 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/rotate-top-right-hover@2x.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/rotate-top-right.png b/src/libs/vmisc/share/resources/icon/32x32/rotate-top-right.png new file mode 100644 index 000000000..aa5fb25de Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/rotate-top-right.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/rotate-top-right@2x.png b/src/libs/vmisc/share/resources/icon/32x32/rotate-top-right@2x.png new file mode 100644 index 000000000..58458f511 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/rotate-top-right@2x.png differ diff --git a/src/libs/vmisc/share/resources/icon/svg/broken_path.svg b/src/libs/vmisc/share/resources/icon/svg/broken_path.svg new file mode 100644 index 000000000..3cafa6dbf --- /dev/null +++ b/src/libs/vmisc/share/resources/icon/svg/broken_path.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/libs/vmisc/vvalentinasettings.cpp b/src/libs/vmisc/vvalentinasettings.cpp index 070658471..e2f1052ab 100644 --- a/src/libs/vmisc/vvalentinasettings.cpp +++ b/src/libs/vmisc/vvalentinasettings.cpp @@ -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 { diff --git a/src/libs/vmisc/vvalentinasettings.h b/src/libs/vmisc/vvalentinasettings.h index e1c42d3ce..032dc29e8 100644 --- a/src/libs/vmisc/vvalentinasettings.h +++ b/src/libs/vmisc/vvalentinasettings.h @@ -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(); diff --git a/src/libs/vpropertyexplorer/plugins/vboolproperty.cpp b/src/libs/vpropertyexplorer/plugins/vboolproperty.cpp index 2e776c036..db7ada18e 100644 --- a/src/libs/vpropertyexplorer/plugins/vboolproperty.cpp +++ b/src/libs/vpropertyexplorer/plugins/vboolproperty.cpp @@ -20,61 +20,95 @@ #include "vboolproperty.h" +#include +#include #include #include #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(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(data.toInt())); + return false; + } + + auto* tmpEditor = qobject_cast(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(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 ); +} diff --git a/src/libs/vpropertyexplorer/plugins/vboolproperty.h b/src/libs/vpropertyexplorer/plugins/vboolproperty.h index a643f84af..8fcb95df3 100644 --- a/src/libs/vpropertyexplorer/plugins/vboolproperty.h +++ b/src/libs/vpropertyexplorer/plugins/vboolproperty.h @@ -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 diff --git a/src/libs/vtools/tools/backgroundimage/vbackgroundimagecontrols.cpp b/src/libs/vtools/tools/backgroundimage/vbackgroundimagecontrols.cpp new file mode 100644 index 000000000..76c89f86a --- /dev/null +++ b/src/libs/vtools/tools/backgroundimage/vbackgroundimagecontrols.cpp @@ -0,0 +1,1895 @@ +/************************************************************************ + ** + ** @file vbackgroundimagecontrols.cpp + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ +#include "vbackgroundimagecontrols.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../ifc/xml/vabstractpattern.h" +#include "vbackgroundimageitem.h" +#include "../vwidgets/global.h" +#include "../vmisc/vabstractvalapplication.h" +#include "../../undocommands/image/scalebackgroundimage.h" +#include "../../undocommands/image/rotatebackgroundimage.h" +#include "../vmisc/vmath.h" +#include "../vwidgets/vmaingraphicsview.h" + +extern auto qt_regionToPath(const QRegion ®ion) -> QPainterPath; + +namespace +{ +//--------------------------------------------------------------------------------------------------------------------- +auto PixmapToPainterPath(const QPixmap &pixmap) -> QPainterPath +{ + if (not pixmap.isNull()) + { + QBitmap mask = pixmap.mask(); + if (not mask.isNull()) + { + return qt_regionToPath(QRegion(mask)); + } + } + + return {}; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto RectTopPoint(const QRectF &rect) -> QPointF +{ + QLineF edge(rect.topLeft(), rect.topRight()); + edge.setLength(edge.length()/2.); + return edge.p2(); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto RectRightPoint(const QRectF &rect) -> QPointF +{ + QLineF edge(rect.topRight(), rect.bottomRight()); + edge.setLength(edge.length()/2.); + return edge.p2(); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto RectBottomPoint(const QRectF &rect) -> QPointF +{ + QLineF edge(rect.bottomLeft(), rect.bottomRight()); + edge.setLength(edge.length()/2.); + return edge.p2(); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto RectLeftPoint(const QRectF &rect) -> QPointF +{ + QLineF edge(rect.bottomLeft(), rect.topLeft()); + edge.setLength(edge.length()/2.); + return edge.p2(); +} +} // namespace + +//--------------------------------------------------------------------------------------------------------------------- +VBackgroundImageControls::VBackgroundImageControls(VAbstractPattern *doc, QGraphicsItem * parent) + : QGraphicsObject(parent), + m_doc(doc) +{ + SCASSERT(doc != nullptr) + setVisible(false); + setFlag(QGraphicsItem::ItemIgnoresTransformations); + setZValue(100); + setAcceptHoverEvents(true); + SetItemOverrideCursor(this, cursorArrowOpenHand, 1, 1); + + InitPixmaps(); + +#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) + QGuiApplication *guiApp = qGuiApp; + if (guiApp != nullptr) + { + connect(guiApp, &QGuiApplication::primaryScreenChanged, this, &VBackgroundImageControls::ScreenChanged); + } +#endif +} + + +//--------------------------------------------------------------------------------------------------------------------- +void VBackgroundImageControls::ActivateControls(const QUuid &id) +{ + if (id.isNull()) + { + m_id = id; + emit ActiveImageChanged(m_id); + setVisible(false); + } + else if (m_id == id) + { + prepareGeometryChange(); + if (m_tranformationType == BITransformationType::Scale) + { + m_tranformationType = BITransformationType::Rotate; + ShowOrigin(m_image.BoundingRect().center()); + } + else if (m_tranformationType == BITransformationType::Rotate) + { + m_tranformationType = BITransformationType::Scale; + m_showOrigin = false; + } + } + else + { + prepareGeometryChange(); + m_id = id; + m_image = m_doc->GetBackgroundImage(m_id); + m_tranformationType = BITransformationType::Scale; + m_showOrigin = false; + emit ActiveImageChanged(m_id); + setVisible(true); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VBackgroundImageControls::DeactivateControls(QGraphicsItem *item) +{ + if (m_transformationApplied) + { + m_transformationApplied = false; + return; + } + + if (item == nullptr) + { + setVisible(false); + m_id = QUuid(); + emit ActiveImageChanged(m_id); + return; + } + + if (item->type() == type() || + item->type() == UserType + static_cast(Tool::BackgroundPixmapImage) || + item->type() == UserType + static_cast(Tool::BackgroundSVGImage)) + { + return; + } + + setVisible(false); + m_id = QUuid(); + emit ActiveImageChanged(m_id); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VBackgroundImageControls::UpdateControls() +{ + if (not isVisible() || m_id.isNull() || m_tranformationType == BITransformationType::Unknown) + { + return; + } + + prepareGeometryChange(); + m_image = m_doc->GetBackgroundImage(m_id); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::boundingRect() const -> QRectF +{ + QRectF boundingRect; + + auto HandlerBoundingRect = [this, &boundingRect](BIHandleCorner corner, BIHandleCornerType type, QPointF pos) + { + QPixmap handler = HandlerPixmap(m_handleCornerHover == corner, type); + boundingRect = boundingRect.united(QRectF(pos, handler.size() / handler.devicePixelRatio())); + }; + + if (m_tranformationType == BITransformationType::Scale) + { + HandlerBoundingRect(BIHandleCorner::TopLeft, BIHandleCornerType::ScaleTopLeftBottomRight, + TopLeftHandlerPosition()); + HandlerBoundingRect(BIHandleCorner::Top, BIHandleCornerType::ScaleTopBottom, + TopHandlerPosition()); + HandlerBoundingRect(BIHandleCorner::TopRight, BIHandleCornerType::ScaleTopRightBottomLeft, + TopRightHandlerPosition()); + HandlerBoundingRect(BIHandleCorner::Right, BIHandleCornerType::ScaleRightLeft, + RightHandlerPosition()); + HandlerBoundingRect(BIHandleCorner::BottomRight, BIHandleCornerType::ScaleTopLeftBottomRight, + BottomRightHandlerPosition()); + HandlerBoundingRect(BIHandleCorner::Bottom, BIHandleCornerType::ScaleTopBottom, + BottomHandlerPosition()); + HandlerBoundingRect(BIHandleCorner::BottomLeft, BIHandleCornerType::ScaleTopRightBottomLeft, + BottomLeftHandlerPosition()); + HandlerBoundingRect(BIHandleCorner::Left, BIHandleCornerType::ScaleRightLeft, + LeftHandlerPosition()); + + } + else if (m_tranformationType == BITransformationType::Rotate) + { + HandlerBoundingRect(BIHandleCorner::TopLeft, BIHandleCornerType::RotateTopLeft, TopLeftHandlerPosition()); + HandlerBoundingRect(BIHandleCorner::TopRight, BIHandleCornerType::RotateTopRight, TopRightHandlerPosition()); + HandlerBoundingRect(BIHandleCorner::BottomRight, BIHandleCornerType::RotateBottomRight, + BottomRightHandlerPosition()); + HandlerBoundingRect(BIHandleCorner::BottomLeft, BIHandleCornerType::RotateBottomLeft, + BottomLeftHandlerPosition()); + } + + boundingRect = boundingRect.united(OriginPath().boundingRect()); + + return boundingRect; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::shape() const -> QPainterPath +{ + QPainterPath shape; + shape.addPath(Handles()); + shape.addPath(OriginPath()); + return shape; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VBackgroundImageControls::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option) + Q_UNUSED(widget) + + if (m_controlsVisible) + { + if (m_tranformationType == BITransformationType::Scale) + { + painter->drawPixmap(TopLeftHandlerPosition(), + HandlerPixmap(m_handleCornerHover == BIHandleCorner::TopLeft, + BIHandleCornerType::ScaleTopLeftBottomRight)); + painter->drawPixmap(TopHandlerPosition(), + HandlerPixmap(m_handleCornerHover == BIHandleCorner::Top, + BIHandleCornerType::ScaleTopBottom)); + painter->drawPixmap(TopRightHandlerPosition(), + HandlerPixmap(m_handleCornerHover == BIHandleCorner::TopRight, + BIHandleCornerType::ScaleTopRightBottomLeft)); + painter->drawPixmap(RightHandlerPosition(), + HandlerPixmap(m_handleCornerHover == BIHandleCorner::Right, + BIHandleCornerType::ScaleRightLeft)); + painter->drawPixmap(BottomRightHandlerPosition(), + HandlerPixmap(m_handleCornerHover == BIHandleCorner::BottomRight, + BIHandleCornerType::ScaleTopLeftBottomRight)); + painter->drawPixmap(BottomHandlerPosition(), + HandlerPixmap(m_handleCornerHover == BIHandleCorner::Bottom, + BIHandleCornerType::ScaleTopBottom)); + painter->drawPixmap(BottomLeftHandlerPosition(), + HandlerPixmap(m_handleCornerHover == BIHandleCorner::BottomLeft, + BIHandleCornerType::ScaleTopRightBottomLeft)); + painter->drawPixmap(LeftHandlerPosition(), + HandlerPixmap(m_handleCornerHover == BIHandleCorner::Left, + BIHandleCornerType::ScaleRightLeft)); + } + else if (m_tranformationType == BITransformationType::Rotate) + { + painter->drawPixmap(TopLeftHandlerPosition(), + HandlerPixmap(m_handleCornerHover == BIHandleCorner::TopLeft, + BIHandleCornerType::RotateTopLeft)); + + painter->drawPixmap(TopRightHandlerPosition(), + HandlerPixmap(m_handleCornerHover == BIHandleCorner::TopRight, + BIHandleCornerType::RotateTopRight)); + + painter->drawPixmap(BottomRightHandlerPosition(), + HandlerPixmap(m_handleCornerHover == BIHandleCorner::BottomRight, + BIHandleCornerType::RotateBottomRight)); + + painter->drawPixmap(BottomLeftHandlerPosition(), + HandlerPixmap(m_handleCornerHover == BIHandleCorner::BottomLeft, + BIHandleCornerType::RotateBottomLeft)); + } + } + + const qreal sceneScale = SceneScale(scene()); + painter->save(); + QPen pen = painter->pen(); + pen.setStyle(Qt::DashLine); + painter->setPen(pen); + + QRectF rect = m_image.BoundingRect(); + rect = QRectF(rect.topLeft()*sceneScale, rect.bottomRight()*sceneScale); + + painter->drawRect(rect.adjusted(-pen.width(), -pen.width(), pen.width(), pen.width())); + painter->restore(); + + if (m_showOrigin) + { + painter->save(); + painter->setBrush(pen.brush()); + painter->drawPath(OriginCircle1()); + painter->restore(); + + painter->save(); + painter->setBrush(QBrush()); + painter->drawPath(OriginCircle2()); + painter->restore(); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VBackgroundImageControls::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + if(event->button() == Qt::LeftButton && event->type() != QEvent::GraphicsSceneMouseDoubleClick) + { + m_transformationApplied = true; + m_controlsVisible = false; + m_handleCornerHover = SelectedHandleCorner(event->pos()); + m_rotationStartPoint = event->pos(); + + if (m_handleCornerHover != BIHandleCorner::Invalid) + { + if (not m_image.Hold()) + { + SetItemOverrideCursor(this, cursorArrowCloseHand, 1, 1); + } + else + { + setCursor(VAbstractValApplication::VApp()->getSceneView()->viewport()->cursor()); + } + } + else + { + setCursor(VAbstractValApplication::VApp()->getSceneView()->viewport()->cursor()); + } + + const qreal sceneScale = SceneScale(scene()); + m_imageBoundingRect = m_image.BoundingRect(); + m_imageScreenBoundingRect = QRectF(m_imageBoundingRect.topLeft()*sceneScale, + QSizeF(m_imageBoundingRect.width()*sceneScale, + m_imageBoundingRect.height()*sceneScale)); + + m_originalMatrix = m_image.Matrix(); + + switch(m_handleCornerHover) + { + case BIHandleCorner::TopLeft: + m_scaleDiff = event->pos() - m_imageScreenBoundingRect.topLeft(); + break; + case BIHandleCorner::Top: + m_scaleDiff = event->pos() - RectTopPoint(m_imageScreenBoundingRect); + break; + case BIHandleCorner::TopRight: + m_scaleDiff = event->pos() - m_imageScreenBoundingRect.topRight(); + break; + case BIHandleCorner::Right: + m_scaleDiff = event->pos() - RectRightPoint(m_imageScreenBoundingRect); + break; + case BIHandleCorner::BottomRight: + m_scaleDiff = event->pos() - m_imageScreenBoundingRect.bottomRight(); + break; + case BIHandleCorner::Bottom: + m_scaleDiff = event->pos() - RectBottomPoint(m_imageScreenBoundingRect); + break; + case BIHandleCorner::BottomLeft: + m_scaleDiff = event->pos() - m_imageScreenBoundingRect.bottomLeft(); + break; + case BIHandleCorner::Left: + m_scaleDiff = event->pos() - RectLeftPoint(m_imageScreenBoundingRect); + break; + case BIHandleCorner::Invalid: + default: + event->ignore(); + break; + } + + event->accept(); + } + else + { + QGraphicsObject::mousePressEvent(event); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VBackgroundImageControls::mouseMoveEvent(QGraphicsSceneMouseEvent *event) +{ + if (m_tranformationType == BITransformationType::Scale) + { + ScaleImage(event); + } + else if (m_tranformationType == BITransformationType::Rotate) + { + RotateImage(event); + } + QGraphicsObject::mouseMoveEvent(event); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VBackgroundImageControls::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + if(event->button() == Qt::LeftButton) + { + if (SelectedHandleCorner(event->pos()) != BIHandleCorner::Invalid) + { + if (not m_image.Hold()) + { + SetItemOverrideCursor(this, cursorArrowOpenHand, 1, 1); + } + else + { + setCursor(VAbstractValApplication::VApp()->getSceneView()->viewport()->cursor()); + } + } + else + { + setCursor(VAbstractValApplication::VApp()->getSceneView()->viewport()->cursor()); + } + + m_controlsVisible = true; + m_allowChangeMerge = false; + + if (m_tranformationType == BITransformationType::Scale) + { + m_showOrigin = false; + } + else if (m_tranformationType == BITransformationType::Rotate) + { + ShowOrigin(m_image.BoundingRect().center()); + } + + update(); + } + else + { + QGraphicsObject::mouseReleaseEvent(event); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VBackgroundImageControls::hoverEnterEvent(QGraphicsSceneHoverEvent *event) +{ + m_handleCornerHover = SelectedHandleCorner(event->pos()); + + if (m_handleCornerHover != BIHandleCorner::Invalid) + { + if (not m_image.Hold()) + { + SetItemOverrideCursor(this, cursorArrowOpenHand, 1, 1); + } + else + { + setCursor(VAbstractValApplication::VApp()->getSceneView()->viewport()->cursor()); + } + } + else + { + setCursor(VAbstractValApplication::VApp()->getSceneView()->viewport()->cursor()); + } + QGraphicsObject::hoverEnterEvent(event); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VBackgroundImageControls::hoverMoveEvent(QGraphicsSceneHoverEvent *event) +{ + m_handleCornerHover = SelectedHandleCorner(event->pos()); + if (m_handleCornerHover != BIHandleCorner::Invalid) + { + if (not m_image.Hold()) + { + SetItemOverrideCursor(this, cursorArrowOpenHand, 1, 1); + } + else + { + setCursor(VAbstractValApplication::VApp()->getSceneView()->viewport()->cursor()); + } + } + else + { + setCursor(VAbstractValApplication::VApp()->getSceneView()->viewport()->cursor()); + } + QGraphicsObject::hoverMoveEvent(event); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VBackgroundImageControls::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) +{ + m_handleCornerHover = BIHandleCorner::Invalid; + + if (SelectedHandleCorner(event->pos()) != BIHandleCorner::Invalid) + { + if (not m_image.Hold()) + { + SetItemOverrideCursor(this, cursorArrowOpenHand, 1, 1); + } + else + { + setCursor(VAbstractValApplication::VApp()->getSceneView()->viewport()->cursor()); + } + } + else + { + setCursor(VAbstractValApplication::VApp()->getSceneView()->viewport()->cursor()); + } + QGraphicsObject::hoverLeaveEvent(event); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VBackgroundImageControls::ScreenChanged() +{ + prepareGeometryChange(); + InitPixmaps(); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::Id() const -> const QUuid & +{ + return m_id; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VBackgroundImageControls::InitPixmaps() +{ + m_handlePixmaps.clear(); + m_handleHoverPixmaps.clear(); + m_handleDisabledPixmaps.clear(); + m_handlePaths.clear(); + + auto InitPixmap = [this](BIHandleCornerType type, const QString &fileName) + { + const QFileInfo fileInfo(fileName); + const QString imageName = fileInfo.baseName(); + + const QString fileNameHover = QStringLiteral("%1/%2-hover.%3") + .arg(fileInfo.absolutePath(), imageName, fileInfo.suffix()); + + const QString fileNameDisabled = QStringLiteral("%1/%2-disabled.%3") + .arg(fileInfo.absolutePath(), imageName, fileInfo.suffix()); + +#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) + if (QGuiApplication::primaryScreen()->devicePixelRatio() >= 2 ) + { + const QString fileName2x = QStringLiteral("%1/%2@2x.%3") + .arg(fileInfo.absolutePath(), imageName, fileInfo.suffix()); + + const QString fileName2xHover = QStringLiteral("%1/%2-hover@2x.%3") + .arg(fileInfo.absolutePath(), imageName, fileInfo.suffix()); + + const QString fileName2xDisabled = QStringLiteral("%1/%2-disabled@2x.%3") + .arg(fileInfo.absolutePath(), imageName, fileInfo.suffix()); + + m_handlePixmaps.insert(type, QPixmap(fileName2x)); + m_handleHoverPixmaps.insert(type, QPixmap(fileName2xHover)); + m_handleDisabledPixmaps.insert(type, QPixmap(fileName2xDisabled)); + } + else + { + m_handlePixmaps.insert(type, QPixmap(fileName)); + m_handleHoverPixmaps.insert(type, QPixmap(fileNameHover)); + m_handleDisabledPixmaps.insert(type, QPixmap(fileNameDisabled)); + } +#else + m_handlePixmaps.insert(type, QPixmap(fileName)); + m_handleHoverPixmaps.insert(type, QPixmap(fileNameHover)); + m_handleDisabledPixmaps.insert(type, QPixmap(fileNameDisabled)); +#endif + QPainterPath p = PixmapToPainterPath(m_handlePixmaps.value(type)); + p.setFillRule(Qt::WindingFill); + p.closeSubpath(); + m_handlePaths.insert(type, p); + }; + + InitPixmap(BIHandleCornerType::ScaleTopLeftBottomRight, QStringLiteral("://icon/32x32/expand2.png")); + InitPixmap(BIHandleCornerType::ScaleTopBottom, QStringLiteral("://icon/32x32/double-arrow-vertical.png")); + InitPixmap(BIHandleCornerType::ScaleTopRightBottomLeft, QStringLiteral("://icon/32x32/expand1.png")); + InitPixmap(BIHandleCornerType::ScaleRightLeft, QStringLiteral("://icon/32x32/double-arrow-horizontal.png")); + InitPixmap(BIHandleCornerType::RotateTopLeft, QStringLiteral("://icon/32x32/rotate-top-left.png")); + InitPixmap(BIHandleCornerType::RotateTopRight, QStringLiteral("://icon/32x32/rotate-top-right.png")); + InitPixmap(BIHandleCornerType::RotateBottomRight, QStringLiteral("://icon/32x32/rotate-bottom-right.png")); + InitPixmap(BIHandleCornerType::RotateBottomLeft, QStringLiteral("://icon/32x32/rotate-bottom-left.png")); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::TopLeftHandlerPosition() const -> QPointF +{ + return ControllersRect().topLeft(); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::TopHandlerPosition() const -> QPointF +{ + QRectF rect = ControllersRect(); + QPixmap handler = m_handlePixmaps.value(BIHandleCornerType::ScaleTopBottom); + QSize size = handler.size() / handler.devicePixelRatio(); + return {rect.topLeft().x() + (rect.width()/2. - size.width()/2.), rect.topLeft().y()}; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::TopRightHandlerPosition() const -> QPointF +{ + QRectF rect = ControllersRect(); + QPixmap handler = m_handlePixmaps.value(BIHandleCornerType::ScaleTopRightBottomLeft); + QSize size = handler.size() / handler.devicePixelRatio(); + return {rect.topLeft().x() + (rect.width() - size.width()), rect.topLeft().y()}; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::RightHandlerPosition() const -> QPointF +{ + QRectF rect = ControllersRect(); + QPixmap handler = m_handlePixmaps.value(BIHandleCornerType::ScaleRightLeft); + QSize size = handler.size() / handler.devicePixelRatio(); + return {rect.topLeft().x() + (rect.width() - size.width()), + rect.topLeft().y() + (rect.height()/2. - size.height()/2.)}; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::BottomRightHandlerPosition() const -> QPointF +{ + QRectF rect = ControllersRect(); + QPixmap handler = m_handlePixmaps.value(BIHandleCornerType::ScaleTopLeftBottomRight); + QSize size = handler.size() / handler.devicePixelRatio(); + return {rect.topLeft().x() + (rect.width() - size.width()), + rect.topLeft().y() + (rect.height() - size.height())}; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::BottomHandlerPosition() const -> QPointF +{ + QRectF rect = ControllersRect(); + QPixmap handler = m_handlePixmaps.value(BIHandleCornerType::ScaleTopBottom); + QSize size = handler.size() / handler.devicePixelRatio(); + return {rect.topLeft().x() + (rect.width()/2. - size.width()/2.), + rect.topLeft().y() + (rect.height() - size.height())}; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::BottomLeftHandlerPosition() const -> QPointF +{ + QRectF rect = ControllersRect(); + QPixmap handler = m_handlePixmaps.value(BIHandleCornerType::ScaleTopRightBottomLeft); + QSize size = handler.size() / handler.devicePixelRatio(); + return {rect.topLeft().x(), rect.topLeft().y() + (rect.height() - size.height())}; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::LeftHandlerPosition() const -> QPointF +{ + QRectF rect = ControllersRect(); + QPixmap handler = m_handlePixmaps.value(BIHandleCornerType::ScaleRightLeft); + QSize size = handler.size() / handler.devicePixelRatio(); + return {rect.topLeft().x(), rect.topLeft().y() + (rect.height()/2. - size.height()/2.)}; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::ControllerPath(BIHandleCornerType type, QPointF pos) const -> QPainterPath +{ + QTransform t; + t.translate(pos.x(), pos.y()); + + QPainterPath controller = m_handlePaths.value(type); + + controller = t.map(controller); + + return controller; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::ScaleTopLeftControl() const -> QPainterPath +{ + return ControllerPath(BIHandleCornerType::ScaleTopLeftBottomRight, TopLeftHandlerPosition()); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::ScaleTopControl() const -> QPainterPath +{ + return ControllerPath(BIHandleCornerType::ScaleTopBottom, TopHandlerPosition()); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::ScaleTopRightControl() const -> QPainterPath +{ + return ControllerPath(BIHandleCornerType::ScaleTopRightBottomLeft, TopRightHandlerPosition()); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::ScaleRightControl() const -> QPainterPath +{ + return ControllerPath(BIHandleCornerType::ScaleRightLeft, RightHandlerPosition()); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::ScaleBottomRightControl() const -> QPainterPath +{ + return ControllerPath(BIHandleCornerType::ScaleTopLeftBottomRight, BottomRightHandlerPosition()); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::ScaleBottomControl() const -> QPainterPath +{ + return ControllerPath(BIHandleCornerType::ScaleTopBottom, BottomHandlerPosition()); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::ScaleBottomLeftControl() const -> QPainterPath +{ + return ControllerPath(BIHandleCornerType::ScaleTopRightBottomLeft, BottomLeftHandlerPosition()); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::ScaleLeftControl() const -> QPainterPath +{ + return ControllerPath(BIHandleCornerType::ScaleRightLeft, LeftHandlerPosition()); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::RotateTopLeftControl() const -> QPainterPath +{ + return ControllerPath(BIHandleCornerType::RotateTopLeft, TopLeftHandlerPosition()); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::RotateTopRightControl() const -> QPainterPath +{ + return ControllerPath(BIHandleCornerType::RotateTopRight, TopRightHandlerPosition()); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::RotateBottomRightControl() const -> QPainterPath +{ + return ControllerPath(BIHandleCornerType::RotateBottomRight, BottomRightHandlerPosition()); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::RotateBottomLeftControl() const -> QPainterPath +{ + return ControllerPath(BIHandleCornerType::RotateBottomLeft, BottomLeftHandlerPosition()); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::ScaleByTopLeft(QGraphicsSceneMouseEvent *event) const -> QTransform +{ + QRectF rectOriginal = m_imageBoundingRect; + QRectF rect = m_imageScreenBoundingRect; + + const qreal adjustmentX = -rect.topLeft().x(); + const qreal adjustmentY = -rect.topLeft().y(); + + rect.translate(adjustmentX, adjustmentY); + + QPointF pos = event->pos(); + pos.rx() += adjustmentX; + pos.ry() += adjustmentY; + + QRectF nowRect; + QPointF diff; + + if (event->modifiers() & Qt::ShiftModifier) + { + nowRect = rect; + + QPointF centerScalePoint = pos - m_scaleDiff; + + if (centerScalePoint.x() > rect.center().x()) + { + centerScalePoint.rx() = rect.center().x() - (centerScalePoint.x() - rect.center().x()); + } + + if (centerScalePoint.y() > rect.center().y()) + { + centerScalePoint.ry() = rect.center().y() - (centerScalePoint.y() - rect.center().y()); + } + + diff = centerScalePoint - rect.topLeft(); + + if (event->modifiers() & Qt::ControlModifier) + { + nowRect.adjust(diff.x(), diff.y(), -diff.x(), -diff.y()); + } + else + { + qreal move; + if (diff.x() > 0 && diff.x() >= diff.y()) + { + move = diff.x(); + } + else if (diff.y() > 0 && diff.y() >= diff.x()) + { + move = diff.y(); + } + else + { + move = qMax(diff.x(), diff.y()); + } + + nowRect.adjust(move, move, -move, -move); + } + } + else + { + QPointF newScalePoint = pos - m_scaleDiff; + + if (newScalePoint.x() > rect.bottomRight().x()) + { + newScalePoint.rx() = rect.bottomRight().x() - (newScalePoint.x() - rect.bottomRight().x()); + } + + if (newScalePoint.y() > rect.bottomRight().y()) + { + newScalePoint.ry() = rect.bottomRight().y()- (newScalePoint.y() - rect.bottomRight().y()); + } + + diff = newScalePoint - rect.topLeft(); + + nowRect = QRectF(newScalePoint, rect.bottomRight()); + } + + qreal scaleX = nowRect.width()/rect.width(); + qreal scaleY = nowRect.height()/rect.height(); + + if (not (event->modifiers() & Qt::ControlModifier)) + { + if (diff.x() > 0 && diff.x() >= diff.y()) + { + scaleY = scaleX; + } + else if (diff.y() > 0 && diff.y() >= diff.x()) + { + scaleX = scaleY; + } + else + { + scaleX = qMin(scaleX, scaleY); + scaleY = qMin(scaleX, scaleY); + } + } + + QPointF newScalePoint = pos - m_scaleDiff; + + QTransform m; + + QPointF scaleCenterOriginal = event->modifiers() & Qt::ShiftModifier ? rectOriginal.center() + : rectOriginal.bottomRight(); + + m.translate(scaleCenterOriginal.x(), scaleCenterOriginal.y()); + + m.scale(scaleX, scaleY); + + QPointF scaleCenter = event->modifiers() & Qt::ShiftModifier ? rect.center() : rect.bottomRight(); + + if (newScalePoint.x() > scaleCenter.x()) + { + m.scale(-1, 1); + } + + if (newScalePoint.y() > scaleCenter.y()) + { + m.scale(1, -1); + } + + m.translate(-scaleCenterOriginal.x(), -scaleCenterOriginal.y()); + + return m; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::ScaleByTop(QGraphicsSceneMouseEvent *event) const -> QTransform +{ + QRectF rectOriginal = m_imageBoundingRect; + QRectF rect = m_imageScreenBoundingRect; + + const qreal adjustmentX = -rect.topLeft().x(); + const qreal adjustmentY = -rect.topLeft().y(); + + rect.translate(adjustmentX, adjustmentY); + + QPointF pos = event->pos(); + pos.rx() += adjustmentX; + pos.ry() += adjustmentY; + + QRectF nowRect; + if (event->modifiers() & Qt::ShiftModifier) + { + nowRect = rect; + + QPointF centerScalePoint = pos - m_scaleDiff; + + if (centerScalePoint.y() > rect.center().y()) + { + centerScalePoint.ry() = rect.center().y() - (centerScalePoint.y() - rect.center().y()); + } + + QPointF diff = centerScalePoint - RectTopPoint(rect); + + if (event->modifiers() & Qt::ControlModifier) + { + nowRect.adjust(0, diff.y(), 0, -diff.y()); + } + else + { + nowRect.adjust(diff.x(), diff.y(), -diff.x(), -diff.y()); + } + } + else + { + QPointF newScalePoint = pos - m_scaleDiff; + + if (newScalePoint.y() > RectBottomPoint(rect).y()) + { + newScalePoint.ry() = RectBottomPoint(rect).y() - (newScalePoint.y() - RectBottomPoint(rect).y()); + } + + nowRect = QRectF(QPointF(rect.topLeft().x(), newScalePoint.y()), rect.bottomRight()); + } + + qreal scaleX = nowRect.height()/rect.height(); + qreal scaleY = nowRect.height()/rect.height(); + + if (event->modifiers() & Qt::ControlModifier) + { + scaleX = 1; + } + + QPointF newScalePoint = pos - m_scaleDiff; + + QTransform m; + + QPointF scaleCenterOriginal = event->modifiers() & Qt::ShiftModifier ? rectOriginal.center() + : RectBottomPoint(rectOriginal); + + m.translate(scaleCenterOriginal.x(), scaleCenterOriginal.y()); + m.scale(scaleX, scaleY); + + QPointF scaleCenter = event->modifiers() & Qt::ShiftModifier ? rect.center() : rect.bottomRight(); + + if (newScalePoint.y() > scaleCenter.y()) + { + m.scale(1, -1); + } + + m.translate(-scaleCenterOriginal.x(), -scaleCenterOriginal.y()); + + return m; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::ScaleByTopRight(QGraphicsSceneMouseEvent *event) const -> QTransform +{ + QRectF rectOriginal = m_imageBoundingRect; + QRectF rect = m_imageScreenBoundingRect; + + const qreal adjustmentX = -rect.topLeft().x(); + const qreal adjustmentY = -rect.topLeft().y(); + + rect.translate(adjustmentX, adjustmentY); + + QPointF pos = event->pos(); + pos.rx() += adjustmentX; + pos.ry() += adjustmentY; + + QRectF nowRect; + QPointF diff; + + if (event->modifiers() & Qt::ShiftModifier) + { + nowRect = rect; + + QPointF centerScalePoint = pos - m_scaleDiff; + + if (centerScalePoint.x() < rect.center().x()) + { + centerScalePoint.rx() = rect.center().x() + (rect.center().x() - centerScalePoint.x()); + } + + if (centerScalePoint.y() > rect.center().y()) + { + centerScalePoint.ry() = rect.center().y() - (centerScalePoint.y() - rect.center().y()); + } + + diff = centerScalePoint - rect.topRight(); + + if (event->modifiers() & Qt::ControlModifier) + { + nowRect.adjust(-diff.x(), diff.y(), diff.x(), -diff.y()); + } + else + { + qreal move; + if (diff.x() < 0 && qAbs(diff.x()) >= qAbs(diff.y())) + { + move = diff.x() * -1; + } + else if (diff.y() > 0 && qAbs(diff.y()) >= qAbs(diff.x())) + { + move = diff.y(); + } + else + { + if (qAbs(diff.x()) <= qAbs(diff.y())) + { + move = diff.x() * -1; + } + else + { + move = diff.y(); + } + } + + nowRect.adjust(move, move, -move, -move); + } + } + else + { + QPointF newScalePoint = pos - m_scaleDiff; + + if (newScalePoint.x() < rect.bottomLeft().x()) + { + newScalePoint.rx() = (rect.bottomLeft().x() - newScalePoint.x()) - rect.bottomLeft().x(); + } + + if (newScalePoint.y() > rect.bottomLeft().y()) + { + newScalePoint.ry() = rect.bottomLeft().y() - (newScalePoint.y() - rect.bottomLeft().y()); + } + + diff = newScalePoint - rect.topRight(); + + nowRect = QRectF(QPointF(rect.topLeft().x(), newScalePoint.y()), + QPointF(newScalePoint.x(), rect.bottomRight().y())); + } + + qreal scaleX = nowRect.width()/rect.width(); + qreal scaleY = nowRect.height()/rect.height(); + + if (not (event->modifiers() & Qt::ControlModifier)) + { + if (diff.x() < 0 && qAbs(diff.x()) >= qAbs(diff.y())) + { + scaleY = scaleX; + } + else if (diff.y() > 0 && qAbs(diff.y()) >= qAbs(diff.x())) + { + scaleX = scaleY; + } + else + { + scaleX = qMin(scaleX, scaleY); + scaleY = qMin(scaleX, scaleY); + } + } + + QPointF newScalePoint = pos - m_scaleDiff; + + QTransform m; + QPointF scaleCenterOriginal = event->modifiers() & Qt::ShiftModifier ? rectOriginal.center() + : rectOriginal.bottomLeft(); + + m.translate(scaleCenterOriginal.x(), scaleCenterOriginal.y()); + m.scale(scaleX, scaleY); + + QPointF scaleCenter = event->modifiers() & Qt::ShiftModifier ? rect.center() : rect.bottomLeft(); + + if (newScalePoint.x() < scaleCenter.x()) + { + m.scale(-1, 1); + } + + if (newScalePoint.y() > scaleCenter.y()) + { + m.scale(1, -1); + } + + m.translate(-scaleCenterOriginal.x(), -scaleCenterOriginal.y()); + + return m; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::ScaleByRight(QGraphicsSceneMouseEvent *event) const -> QTransform +{ + QRectF rectOriginal = m_imageBoundingRect; + QRectF rect = m_imageScreenBoundingRect; + + const qreal adjustmentX = -rect.topLeft().x(); + const qreal adjustmentY = -rect.topLeft().y(); + + rect.translate(adjustmentX, adjustmentY); + + QPointF pos = event->pos(); + pos.rx() += adjustmentX; + pos.ry() += adjustmentY; + + QRectF nowRect; + + if (event->modifiers() & Qt::ShiftModifier) + { + nowRect = rect; + + QPointF centerScalePoint = pos - m_scaleDiff; + + if (centerScalePoint.x() < rect.center().x()) + { + centerScalePoint.rx() = rect.center().x() + (rect.center().x() - centerScalePoint.x()); + } + + QPointF diff = centerScalePoint - RectRightPoint(rect); + + if (event->modifiers() & Qt::ControlModifier) + { + nowRect.adjust(-diff.x(), 0, diff.x(), 0); + } + else + { + nowRect.adjust(-diff.x(), -diff.y(), diff.x(), diff.y()); + } + } + else + { + QPointF newScalePoint = pos - m_scaleDiff; + + if (newScalePoint.x() < RectLeftPoint(rect).x()) + { + newScalePoint.rx() = (RectLeftPoint(rect).x() - newScalePoint.x()) - RectLeftPoint(rect).x(); + } + + nowRect = QRectF(rect.topLeft(), QPointF(newScalePoint.x(), rect.bottomRight().y())); + } + + qreal scaleX = nowRect.width()/rect.width(); + qreal scaleY = nowRect.width()/rect.width(); + + if (event->modifiers() & Qt::ControlModifier) + { + scaleY = 1; + } + + QPointF newScalePoint = pos - m_scaleDiff; + + QTransform m; + + QPointF scaleCenterOriginal = event->modifiers() & Qt::ShiftModifier ? rectOriginal.center() + : RectLeftPoint(rectOriginal); + + m.translate(scaleCenterOriginal.x(), scaleCenterOriginal.y()); + m.scale(scaleX, scaleY); + + QPointF scaleCenter = event->modifiers() & Qt::ShiftModifier ? rect.center() : RectLeftPoint(rect); + + if (newScalePoint.x() < scaleCenter.x()) + { + m.scale(-1, 1); + } + + m.translate(-scaleCenterOriginal.x(), -scaleCenterOriginal.y()); + + return m; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::ScaleByBottomRight(QGraphicsSceneMouseEvent *event) const -> QTransform +{ + QRectF rectOriginal = m_imageBoundingRect; + QRectF rect = m_imageScreenBoundingRect; + + // move to origin + const qreal adjustmentX = -rect.topLeft().x(); + const qreal adjustmentY = -rect.topLeft().y(); + + rect.translate(adjustmentX, adjustmentY); + + QPointF pos = event->pos(); + pos.rx() += adjustmentX; + pos.ry() += adjustmentY; + + QRectF nowRect; + QPointF diff; + + if (event->modifiers() & Qt::ShiftModifier) + { + nowRect = rect; + + QPointF centerScalePoint = pos - m_scaleDiff; + + if (centerScalePoint.x() < rect.center().x()) + { + centerScalePoint.rx() = rect.center().x() + (rect.center().x() - centerScalePoint.x()); + } + + if (centerScalePoint.y() < rect.center().y()) + { + centerScalePoint.ry() = rect.center().y() + (rect.center().y() - centerScalePoint.y()); + } + + diff = centerScalePoint - rect.bottomRight(); + + if (event->modifiers() & Qt::ControlModifier) + { + nowRect.adjust(-diff.x(), -diff.y(), diff.x(), diff.y()); + } + else + { + qreal move; + if (diff.x() < 0 && diff.x() <= diff.y()) + { + move = diff.x(); + } + else if (diff.y() < 0 && diff.y() <= diff.x()) + { + move = diff.y(); + } + else + { + move = qMin(diff.x(), diff.y()); + } + nowRect.adjust(-move, -move, move, move); + } + } + else + { + // correct the scale point position to match the rect at origin + QPointF newScalePoint = pos - m_scaleDiff; + + if (newScalePoint.x() < rect.topLeft().x()) + { + newScalePoint.rx() = rect.topLeft().x() + (rect.topLeft().x() - newScalePoint.x()); + } + + if (newScalePoint.y() < rect.topLeft().y()) + { + newScalePoint.ry() = rect.topLeft().y() + (rect.topLeft().y() - newScalePoint.y()); + } + + // calculate scale + diff = newScalePoint - rect.bottomRight(); + + nowRect = QRectF(rect.topLeft(), newScalePoint); + } + + qreal scaleX = nowRect.width()/rect.width(); + qreal scaleY = nowRect.height()/rect.height(); + + if (not (event->modifiers() & Qt::ControlModifier)) + { + if (diff.x() < 0 && diff.x() <= diff.y()) + { + scaleY = scaleX; + } + else if (diff.y() < 0 && diff.y() <= diff.x()) + { + scaleX = scaleY; + } + else + { + scaleX = qMin(scaleX, scaleY); + scaleY = qMin(scaleX, scaleY); + } + } + + // prepare transformation + QPointF newScalePoint = pos - m_scaleDiff; + + QTransform m; + + QPointF scaleCenterOriginal = event->modifiers() & Qt::ShiftModifier ? rectOriginal.center() + : rectOriginal.topLeft(); + + m.translate(scaleCenterOriginal.x(), scaleCenterOriginal.y()); + + m.scale(scaleX, scaleY); + + QPointF scaleCenter = event->modifiers() & Qt::ShiftModifier ? rect.center() : rect.topLeft(); + + if (newScalePoint.x() < scaleCenter.x()) + { + m.scale(-1, 1); + } + + if (newScalePoint.y() < scaleCenter.y()) + { + m.scale(1, -1); + } + + m.translate(-scaleCenterOriginal.x(), -scaleCenterOriginal.y()); + + return m; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::ScaleByBottom(QGraphicsSceneMouseEvent *event) const -> QTransform +{ + QRectF rectOriginal = m_imageBoundingRect; + QRectF rect = m_imageScreenBoundingRect; + + const qreal adjustmentX = -rect.topLeft().x(); + const qreal adjustmentY = -rect.topLeft().y(); + + rect.translate(adjustmentX, adjustmentY); + + QPointF pos = event->pos(); + pos.rx() += adjustmentX; + pos.ry() += adjustmentY; + + QRectF nowRect; + if (event->modifiers() & Qt::ShiftModifier) + { + nowRect = rect; + + QPointF centerScalePoint = pos - m_scaleDiff; + + if (centerScalePoint.y() < rect.center().y()) + { + centerScalePoint.ry() = rect.center().y() + (rect.center().y() - centerScalePoint.y()); + } + + QPointF diff = centerScalePoint - RectBottomPoint(rect); + + if (event->modifiers() & Qt::ControlModifier) + { + nowRect.adjust(0, -diff.y(), 0, diff.y()); + } + else + { + nowRect.adjust(-diff.x(), -diff.y(), diff.x(), diff.y()); + } + } + else + { + QPointF newScalePoint = pos - m_scaleDiff; + + if (newScalePoint.y() < RectTopPoint(rect).y()) + { + newScalePoint.ry() = (RectTopPoint(rect).y() - newScalePoint.y()) - RectTopPoint(rect).y(); + } + + nowRect = QRectF(rect.topLeft(), QPointF(rect.bottomRight().x(), newScalePoint.y())); + } + + qreal scaleX = nowRect.height()/rect.height(); + qreal scaleY = nowRect.height()/rect.height(); + + if (event->modifiers() & Qt::ControlModifier) + { + scaleX = 1; + } + + QPointF newScalePoint = pos - m_scaleDiff; + + QTransform m; + + QPointF scaleCenterOriginal = event->modifiers() & Qt::ShiftModifier ? rectOriginal.center() + : RectTopPoint(rectOriginal); + + m.translate(scaleCenterOriginal.x(), scaleCenterOriginal.y()); + m.scale(scaleX, scaleY); + + QPointF scaleCenter = event->modifiers() & Qt::ShiftModifier ? rect.center() : RectTopPoint(rect); + + if (newScalePoint.y() < scaleCenter.y()) + { + m.scale(1, -1); + } + + m.translate(-scaleCenterOriginal.x(), -scaleCenterOriginal.y()); + + return m; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::ScaleByBottomLeft(QGraphicsSceneMouseEvent *event) const -> QTransform +{ + QRectF rectOriginal = m_imageBoundingRect; + QRectF rect = m_imageScreenBoundingRect; + + const qreal adjustmentX = -rect.topLeft().x(); + const qreal adjustmentY = -rect.topLeft().y(); + + rect.translate(adjustmentX, adjustmentY); + + QPointF pos = event->pos(); + pos.rx() += adjustmentX; + pos.ry() += adjustmentY; + + QRectF nowRect; + QPointF diff; + + if (event->modifiers() & Qt::ShiftModifier) + { + nowRect = rect; + + QPointF centerScalePoint = pos - m_scaleDiff; + + if (centerScalePoint.x() > rect.center().x()) + { + centerScalePoint.rx() = rect.center().x() - (centerScalePoint.x() - rect.center().x()); + } + + if (centerScalePoint.y() < rect.center().y()) + { + centerScalePoint.ry() = rect.center().y() + (rect.center().y() - centerScalePoint.y()); + } + + diff = centerScalePoint - rect.bottomLeft(); + qDebug() << diff; + + if (event->modifiers() & Qt::ControlModifier) + { + nowRect.adjust(diff.x(), -diff.y(), -diff.x(), diff.y()); + } + else + { + qreal move; + if (diff.x() > 0 && diff.x() >= qAbs(diff.y())) + { + move = diff.x(); + } + else if (diff.y() < 0 && qAbs(diff.y()) >= qAbs(diff.x())) + { + move = diff.y() * -1; + } + else + { + if (qAbs(diff.x()) <= qAbs(diff.y())) + { + move = diff.x(); + } + else + { + move = diff.y()*-1; + } + } + qDebug() << move; + nowRect.adjust(move, move, -move, -move); + } + } + else + { + QPointF newScalePoint = pos - m_scaleDiff; + + if (newScalePoint.x() > rect.topRight().x()) + { + newScalePoint.rx() = rect.topRight().x() - (newScalePoint.x() - rect.topRight().x()); + } + + if (newScalePoint.y() < rect.topRight().y()) + { + newScalePoint.ry() = (rect.topRight().y() - newScalePoint.y()) - rect.topRight().y(); + } + + diff = newScalePoint - rect.topRight(); + + nowRect = QRectF(QPointF(newScalePoint.x(), rect.topLeft().y()), + QPointF(rect.bottomRight().x(), newScalePoint.y())); + } + + qreal scaleX = nowRect.width()/rect.width(); + qreal scaleY = nowRect.height()/rect.height(); + + if (not (event->modifiers() & Qt::ControlModifier)) + { + if (diff.x() > 0 && diff.x() >= diff.y()) + { + scaleY = scaleX; + } + else if (diff.y() < 0 && diff.y() >= diff.x()) + { + scaleX = scaleY; + } + else + { + scaleX = qMin(scaleX, scaleY); + scaleY = qMin(scaleX, scaleY); + } + } + + QPointF newScalePoint = pos - m_scaleDiff; + + QTransform m; + QPointF scaleCenterOriginal = event->modifiers() & Qt::ShiftModifier ? rectOriginal.center() + : rectOriginal.topRight(); + + m.translate(scaleCenterOriginal.x(), scaleCenterOriginal.y()); + m.scale(scaleX, scaleY); + + QPointF scaleCenter = event->modifiers() & Qt::ShiftModifier ? rect.center() : rect.topRight(); + + if (newScalePoint.x() > scaleCenter.x()) + { + m.scale(-1, 1); + } + + if (newScalePoint.y() < scaleCenter.y()) + { + m.scale(1, -1); + } + + m.translate(-scaleCenterOriginal.x(), -scaleCenterOriginal.y()); + + return m; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::ScaleByLeft(QGraphicsSceneMouseEvent *event) const -> QTransform +{ + QRectF rectOriginal = m_imageBoundingRect; + QRectF rect = m_imageScreenBoundingRect; + + const qreal adjustmentX = -rect.topLeft().x(); + const qreal adjustmentY = -rect.topLeft().y(); + + rect.translate(adjustmentX, adjustmentY); + + QPointF pos = event->pos(); + pos.rx() += adjustmentX; + pos.ry() += adjustmentY; + + QRectF nowRect; + if (event->modifiers() & Qt::ShiftModifier) + { + nowRect = rect; + + QPointF centerScalePoint = pos - m_scaleDiff; + + if (centerScalePoint.x() > rect.center().x()) + { + centerScalePoint.rx() = rect.center().x() - (centerScalePoint.x() - rect.center().x()); + } + + QPointF diff = centerScalePoint - RectLeftPoint(rect); + + if (event->modifiers() & Qt::ControlModifier) + { + nowRect.adjust(diff.x(), 0, -diff.x(), 0); + } + else + { + nowRect.adjust(diff.x(), diff.y(), -diff.x(), -diff.y()); + } + } + else + { + QPointF newScalePoint = pos - m_scaleDiff; + + if (newScalePoint.x() > RectRightPoint(rect).x()) + { + newScalePoint.rx() = RectRightPoint(rect).x() - (newScalePoint.x() - RectRightPoint(rect).x()); + } + + nowRect = QRectF(QPointF(newScalePoint.x(), rect.topLeft().y()), rect.bottomRight()); + } + + qreal scaleX = nowRect.width()/rect.width(); + qreal scaleY = nowRect.width()/rect.width(); + + if (event->modifiers() & Qt::ControlModifier) + { + scaleY = 1; + } + + QPointF newScalePoint = pos - m_scaleDiff; + + QTransform m; + + QPointF scaleCenterOriginal = event->modifiers() & Qt::ShiftModifier ? rectOriginal.center() + : RectRightPoint(rectOriginal); + + m.translate(scaleCenterOriginal.x(), scaleCenterOriginal.y()); + m.scale(scaleX, scaleY); + + QPointF scaleCenter = event->modifiers() & Qt::ShiftModifier ? rect.center() : RectRightPoint(rect); + + if (newScalePoint.x() > scaleCenter.x()) + { + m.scale(-1, 1); + } + + m.translate(-scaleCenterOriginal.x(), -scaleCenterOriginal.y()); + + return m; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::Handles() const -> QPainterPath +{ + QPainterPath path; + + if (m_tranformationType == BITransformationType::Scale) + { + path.addPath(ScaleTopLeftControl()); + path.addPath(ScaleTopControl()); + path.addPath(ScaleTopRightControl()); + path.addPath(ScaleRightControl()); + path.addPath(ScaleBottomRightControl()); + path.addPath(ScaleBottomControl()); + path.addPath(ScaleBottomLeftControl()); + path.addPath(ScaleLeftControl()); + } + else if (m_tranformationType == BITransformationType::Rotate) + { + path.addPath(RotateTopLeftControl()); + path.addPath(RotateTopRightControl()); + path.addPath(RotateBottomRightControl()); + path.addPath(RotateBottomLeftControl()); + } + + return path; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::ControllersRect() const -> QRectF +{ + const qreal scale = SceneScale(scene()); + QPixmap handler = m_handlePixmaps.value(BIHandleCornerType::ScaleTopLeftBottomRight); + QRectF imageRect = m_image.BoundingRect(); + + imageRect = QRectF(imageRect.topLeft()*scale, QSizeF(imageRect.width()*scale, imageRect.height()*scale)); + QRectF rect = imageRect; + + if (imageRect.width() < handler.width()) + { + qreal diff = handler.width() - imageRect.width(); + rect.adjust(0, 0, diff, 0); + } + + if (imageRect.height() < handler.height()) + { + qreal diff = handler.height() - imageRect.height(); + rect.adjust(0, 0, 0, diff); + } + + const qreal gap = 2; + rect.adjust(- (handler.width() + gap), - (handler.height() + gap), handler.width() + gap, handler.height() + gap); + + return rect; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::SelectedHandleCorner(const QPointF &pos) const -> BIHandleCorner +{ + if (m_image.Hold()) + { + return BIHandleCorner::Invalid; + } + + QMap corners; + + if (m_tranformationType == BITransformationType::Scale) + { + corners = + { + {BIHandleCorner::TopLeft, ScaleTopLeftControl()}, + {BIHandleCorner::Top, ScaleTopControl()}, + {BIHandleCorner::TopRight, ScaleTopRightControl()}, + {BIHandleCorner::Right, ScaleRightControl()}, + {BIHandleCorner::BottomRight, ScaleBottomRightControl()}, + {BIHandleCorner::Bottom, ScaleBottomControl()}, + {BIHandleCorner::BottomLeft, ScaleBottomLeftControl()}, + {BIHandleCorner::Left, ScaleLeftControl()}, + }; + } + else if (m_tranformationType == BITransformationType::Rotate) + { + corners = + { + {BIHandleCorner::TopLeft, RotateTopLeftControl()}, + {BIHandleCorner::TopRight, RotateTopRightControl()}, + {BIHandleCorner::BottomRight, RotateBottomRightControl()}, + {BIHandleCorner::BottomLeft, RotateBottomLeftControl()}, + }; + } + + QPainterPath circle; + circle.addEllipse(pos.x()-4, pos.y()-4, 8, 8); + + auto CheckCorner = [circle](const QPainterPath &handler) + { + return handler.intersects(circle) || handler.contains(circle); + }; + + auto i = corners.constBegin(); + while (i != corners.constEnd()) + { + if (CheckCorner(i.value())) + { + return i.key(); + } + ++i; + } + + return BIHandleCorner::Invalid; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::HandlerPixmap(bool hover, BIHandleCornerType type) const -> QPixmap +{ + if (not m_image.Hold()) + { + return hover ? m_handleHoverPixmaps.value(type) : m_handlePixmaps.value(type); + } + + return m_handleDisabledPixmaps.value(type); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VBackgroundImageControls::ShowOrigin(const QPointF &pos) +{ + prepareGeometryChange(); + m_showOrigin = true; + m_originPos = pos; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::OriginCircle1() const -> QPainterPath +{ + const qreal radius1 = 4; + QPainterPath path; + const qreal sceneScale = SceneScale(scene()); + QPointF screeOrigin = m_originPos * sceneScale; + path.addEllipse({screeOrigin.x()-radius1, screeOrigin.y()-radius1, radius1*2., radius1*2.}); + return path; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::OriginCircle2() const -> QPainterPath +{ + const qreal radius2 = 8; + QPainterPath path; + const qreal sceneScale = SceneScale(scene()); + QPointF screeOrigin = m_originPos * sceneScale; + path.addEllipse({screeOrigin.x()-radius2, screeOrigin.y()-radius2, radius2*2., radius2*2.}); + return path; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VBackgroundImageControls::OriginPath() const -> QPainterPath +{ + QPainterPath path; + + if (m_showOrigin) + { + path.addPath(OriginCircle1()); + path.addPath(OriginCircle2()); + } + + return path; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VBackgroundImageControls::ScaleImage(QGraphicsSceneMouseEvent *event) +{ + QTransform imageMatrix = m_originalMatrix; + const bool shiftModifier = event->modifiers() & Qt::ShiftModifier; + + switch(m_handleCornerHover) + { + case BIHandleCorner::TopLeft: + ShowOrigin(shiftModifier ? m_imageBoundingRect.center() + : m_imageBoundingRect.bottomRight()); + imageMatrix *= ScaleByTopLeft(event); + break; + case BIHandleCorner::Top: + ShowOrigin(shiftModifier ? m_imageBoundingRect.center() + : RectBottomPoint(m_imageBoundingRect)); + imageMatrix *= ScaleByTop(event); + break; + case BIHandleCorner::TopRight: + ShowOrigin(shiftModifier ? m_imageBoundingRect.center() + : m_imageBoundingRect.bottomLeft()); + imageMatrix *= ScaleByTopRight(event); + break; + case BIHandleCorner::Right: + ShowOrigin(shiftModifier ? m_imageBoundingRect.center() + : RectLeftPoint(m_imageBoundingRect)); + imageMatrix *= ScaleByRight(event); + break; + case BIHandleCorner::BottomRight: + ShowOrigin(shiftModifier ? m_imageBoundingRect.center() + : m_imageBoundingRect.topLeft()); + imageMatrix *= ScaleByBottomRight(event); + break; + case BIHandleCorner::Bottom: + ShowOrigin(shiftModifier ? m_imageBoundingRect.center() + : RectTopPoint(m_imageBoundingRect)); + imageMatrix *= ScaleByBottom(event); + break; + case BIHandleCorner::BottomLeft: + ShowOrigin(shiftModifier ? m_imageBoundingRect.center() + : m_imageBoundingRect.topRight()); + imageMatrix *= ScaleByBottomLeft(event); + break; + case BIHandleCorner::Left: + ShowOrigin(shiftModifier ? m_imageBoundingRect.center() + : RectRightPoint(m_imageBoundingRect)); + imageMatrix *= ScaleByLeft(event); + break; + case BIHandleCorner::Invalid: + default: + break; + } + + if (m_handleCornerHover != BIHandleCorner::Invalid) + { + auto *command = new ScaleBackgroundImage(m_image.Id(), imageMatrix, m_doc, m_allowChangeMerge); + VAbstractApplication::VApp()->getUndoStack()->push(command); + m_allowChangeMerge = true; + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VBackgroundImageControls::RotateImage(QGraphicsSceneMouseEvent *event) +{ + const bool shiftModifier = event->modifiers() & Qt::ShiftModifier; + + switch(m_handleCornerHover) + { + case BIHandleCorner::TopLeft: + ShowOrigin(shiftModifier ? m_imageBoundingRect.bottomRight() + : m_imageBoundingRect.center()); + break; + case BIHandleCorner::TopRight: + ShowOrigin(shiftModifier ? m_imageBoundingRect.bottomLeft() + : m_imageBoundingRect.center()); + break; + case BIHandleCorner::BottomRight: + ShowOrigin(shiftModifier ? m_imageBoundingRect.topLeft() + : m_imageBoundingRect.center()); + break; + case BIHandleCorner::BottomLeft: + ShowOrigin(shiftModifier ? m_imageBoundingRect.topRight() + : m_imageBoundingRect.center()); + break; + default: + break; + } + + if (m_handleCornerHover != BIHandleCorner::Invalid) + { + QPointF rotationNewPoint = event->pos(); + const qreal sceneScale = SceneScale(scene()); + QPointF screenOriginPos = m_originPos*sceneScale; + + QLineF initPosition(screenOriginPos, m_rotationStartPoint); + QLineF initRotationPosition(screenOriginPos, rotationNewPoint); + + qreal rotateOn = initPosition.angleTo(initRotationPosition); + + if (rotateOn > 180) + { + rotateOn = rotateOn - 360.; + } + + if (event->modifiers() & Qt::ControlModifier) + { + const qreal sign = std::copysign(1.0, rotateOn); + const int steps = qFloor(qAbs(rotateOn / 15)); + rotateOn = 15 * steps * sign; + } + + QTransform imageMatrix = m_originalMatrix; + + QTransform m; + m.translate(m_originPos.x(), m_originPos.y()); + m.rotate(-rotateOn); + m.translate(-m_originPos.x(), -m_originPos.y()); + imageMatrix *= m; + + auto *command = new RotateBackgroundImage(m_image.Id(), imageMatrix, m_doc, m_allowChangeMerge); + VAbstractApplication::VApp()->getUndoStack()->push(command); + m_allowChangeMerge = true; + } +} diff --git a/src/libs/vtools/tools/backgroundimage/vbackgroundimagecontrols.h b/src/libs/vtools/tools/backgroundimage/vbackgroundimagecontrols.h new file mode 100644 index 000000000..ef607f722 --- /dev/null +++ b/src/libs/vtools/tools/backgroundimage/vbackgroundimagecontrols.h @@ -0,0 +1,185 @@ +/************************************************************************ + ** + ** @file vbackgroundimagecontrols.h + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ +#ifndef VBACKGROUNDIMAGECONTROLS_H +#define VBACKGROUNDIMAGECONTROLS_H + +#include +#include + +#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(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 m_handlePixmaps{}; + QMap m_handleHoverPixmaps{}; + QMap m_handleDisabledPixmaps{}; + QMap 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 diff --git a/src/libs/vtools/tools/backgroundimage/vbackgroundimageitem.cpp b/src/libs/vtools/tools/backgroundimage/vbackgroundimageitem.cpp new file mode 100644 index 000000000..d4d44913e --- /dev/null +++ b/src/libs/vtools/tools/backgroundimage/vbackgroundimageitem.cpp @@ -0,0 +1,734 @@ +/************************************************************************ + ** + ** @file vbackgroundimageitem.cpp + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ + +#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 +#include +#include +#include +#include +#include +#include + +//--------------------------------------------------------------------------------------------------------------------- +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 viewList = scene()->views(); + if (not viewList.isEmpty()) + { + if (auto *view = qobject_cast(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 viewList = scene()->views(); + if (not viewList.isEmpty()) + { + if (auto *view = qobject_cast(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); + } +} diff --git a/src/libs/vtools/tools/backgroundimage/vbackgroundimageitem.h b/src/libs/vtools/tools/backgroundimage/vbackgroundimageitem.h new file mode 100644 index 000000000..a779ab9cb --- /dev/null +++ b/src/libs/vtools/tools/backgroundimage/vbackgroundimageitem.h @@ -0,0 +1,133 @@ +/************************************************************************ + ** + ** @file vbackgroundimageitem.h + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ +#ifndef VBACKGROUNDIMAGEITEM_H +#define VBACKGROUNDIMAGEITEM_H + +#include + +#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(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 diff --git a/src/libs/vtools/tools/backgroundimage/vbackgroundpixmapitem.cpp b/src/libs/vtools/tools/backgroundimage/vbackgroundpixmapitem.cpp new file mode 100644 index 000000000..71052ff4a --- /dev/null +++ b/src/libs/vtools/tools/backgroundimage/vbackgroundpixmapitem.cpp @@ -0,0 +1,245 @@ +/************************************************************************ + ** + ** @file vbackgroundpixmapitem.cpp + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ +#include "vbackgroundpixmapitem.h" + +#include +#include +#include +#include +#include + +extern auto qt_regionToPath(const QRegion ®ion) -> 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; +} diff --git a/src/libs/vtools/tools/backgroundimage/vbackgroundpixmapitem.h b/src/libs/vtools/tools/backgroundimage/vbackgroundpixmapitem.h new file mode 100644 index 000000000..fa52beaf6 --- /dev/null +++ b/src/libs/vtools/tools/backgroundimage/vbackgroundpixmapitem.h @@ -0,0 +1,88 @@ +/************************************************************************ + ** + ** @file vbackgroundpixmapitem.h + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ +#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(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 diff --git a/src/libs/vtools/tools/backgroundimage/vbackgroundsvgitem.cpp b/src/libs/vtools/tools/backgroundimage/vbackgroundsvgitem.cpp new file mode 100644 index 000000000..3c4e0836d --- /dev/null +++ b/src/libs/vtools/tools/backgroundimage/vbackgroundsvgitem.cpp @@ -0,0 +1,123 @@ +/************************************************************************ + ** + ** @file vbackgroundsvgitem.cpp + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ +#include "vbackgroundsvgitem.h" + +#include +#include +#include +#include + +//--------------------------------------------------------------------------------------------------------------------- +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; +} diff --git a/src/libs/vtools/tools/backgroundimage/vbackgroundsvgitem.h b/src/libs/vtools/tools/backgroundimage/vbackgroundsvgitem.h new file mode 100644 index 000000000..1e4c934ca --- /dev/null +++ b/src/libs/vtools/tools/backgroundimage/vbackgroundsvgitem.h @@ -0,0 +1,63 @@ +/************************************************************************ + ** + ** @file vbackgroundsvgitem.h + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ +#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(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 diff --git a/src/libs/vtools/tools/tools.pri b/src/libs/vtools/tools/tools.pri index 93eec3025..6fddcfced 100644 --- a/src/libs/vtools/tools/tools.pri +++ b/src/libs/vtools/tools/tools.pri @@ -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 \ diff --git a/src/libs/vtools/tools/toolsdef.cpp b/src/libs/vtools/tools/toolsdef.cpp index 76cde66f3..69b052977 100644 --- a/src/libs/vtools/tools/toolsdef.cpp +++ b/src/libs/vtools/tools/toolsdef.cpp @@ -29,16 +29,21 @@ #include "toolsdef.h" #include +#include #include +#include #include #include #include #include #include +#include #include "../vgeometry/vgobject.h" #include "../qmuparser/qmudef.h" #include "../vpatterndb/vcontainer.h" +#include "../vpropertyexplorer/checkablemessagebox.h" +#include "../vmisc/vabstractvalapplication.h" //--------------------------------------------------------------------------------------------------------------------- QVector SourceToObjects(const QVector &source) @@ -116,3 +121,28 @@ QMap 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; +} diff --git a/src/libs/vtools/tools/toolsdef.h b/src/libs/vtools/tools/toolsdef.h index 52a849942..e68211300 100644 --- a/src/libs/vtools/tools/toolsdef.h +++ b/src/libs/vtools/tools/toolsdef.h @@ -60,4 +60,6 @@ bool SourceAliasValid(const SourceItem &item, const QSharedPointer &ob QMap OperationLineStylesPics(); +int ConfirmDeletion(); + #endif // TOOLSDEF_H diff --git a/src/libs/vtools/tools/vabstracttool.cpp b/src/libs/vtools/tools/vabstracttool.cpp index 81bf46e33..46a6a0728 100644 --- a/src/libs/vtools/tools/vabstracttool.cpp +++ b/src/libs/vtools/tools/vabstracttool.cpp @@ -30,15 +30,11 @@ #include #include -#include #include #include #include #include -#include #include -#include -#include #include #include #include @@ -48,14 +44,13 @@ #include #include #include -#include #include #include #include #include +#include #include "../vgeometry/vpointf.h" -#include "../vpropertyexplorer/checkablemessagebox.h" #include "../vwidgets/vmaingraphicsview.h" #include "../ifc/exception/vexception.h" #include "../ifc/exception/vexceptionundo.h" @@ -77,6 +72,7 @@ #include "nodeDetails/nodedetails.h" #include "../dialogs/support/dialogundo.h" #include "../dialogs/support/dialogeditwrongformula.h" +#include "toolsdef.h" template class QSharedPointer; @@ -246,31 +242,6 @@ void VAbstractTool::PerformDelete() VAbstractApplication::VApp()->getUndoStack()->push(delTool); } -//--------------------------------------------------------------------------------------------------------------------- -int VAbstractTool::ConfirmDeletion() -{ - if (false == VAbstractApplication::VApp()->Settings()->GetConfirmItemDelete()) - { - return QMessageBox::Yes; - } - - Utils::CheckableMessageBox msgBox(VAbstractValApplication::VApp()->getMainWindow()); - msgBox.setWindowTitle(tr("Confirm deletion")); - msgBox.setText(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; -} - //--------------------------------------------------------------------------------------------------------------------- const QStringList VAbstractTool::Colors() { diff --git a/src/libs/vtools/tools/vabstracttool.h b/src/libs/vtools/tools/vabstracttool.h index aa156f780..b7d4de8ba 100644 --- a/src/libs/vtools/tools/vabstracttool.h +++ b/src/libs/vtools/tools/vabstracttool.h @@ -160,7 +160,6 @@ protected: virtual void RemoveReferens() {} virtual void DeleteToolWithConfirm(bool ask = true); virtual void PerformDelete(); - static int ConfirmDeletion(); template static quint32 CreateNode(VContainer *data, quint32 id); diff --git a/src/libs/vtools/tools/vtoolseamallowance.cpp b/src/libs/vtools/tools/vtoolseamallowance.cpp index 6b71582a3..23a68d068 100644 --- a/src/libs/vtools/tools/vtoolseamallowance.cpp +++ b/src/libs/vtools/tools/vtoolseamallowance.cpp @@ -55,6 +55,7 @@ #include "../vwidgets/vabstractmainwindow.h" #include "../qmuparser/qmutokenparser.h" #include "../vlayout/vlayoutdef.h" +#include "toolsdef.h" #include #include @@ -549,7 +550,7 @@ void VToolSeamAllowance::ConnectOutsideSignals() connect(doc, &VAbstractPattern::CheckLayout, this, &VToolSeamAllowance::UpdateGrainline); connect(m_sceneDetails, &VMainGraphicsScene::EnableToolMove, this, &VToolSeamAllowance::EnableToolMove); - connect(m_sceneDetails, &VMainGraphicsScene::ItemClicked, this, &VToolSeamAllowance::ResetChildren); + connect(m_sceneDetails, &VMainGraphicsScene::ItemByMousePress, this, &VToolSeamAllowance::ResetChildren); connect(m_sceneDetails, &VMainGraphicsScene::DimensionsChanged, this, &VToolSeamAllowance::UpdateDetailLabel); connect(m_sceneDetails, &VMainGraphicsScene::DimensionsChanged, this, &VToolSeamAllowance::UpdatePatternInfo); connect(m_sceneDetails, &VMainGraphicsScene::LanguageChanged, this, &VToolSeamAllowance::retranslateUi); diff --git a/src/libs/vtools/undocommands/image/addbackgroundimage.cpp b/src/libs/vtools/undocommands/image/addbackgroundimage.cpp new file mode 100644 index 000000000..e3b39ec41 --- /dev/null +++ b/src/libs/vtools/undocommands/image/addbackgroundimage.cpp @@ -0,0 +1,58 @@ +/************************************************************************ + ** + ** @file addbackgroundimage.cpp + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ +#include "addbackgroundimage.h" + +//--------------------------------------------------------------------------------------------------------------------- +AddBackgroundImage::AddBackgroundImage(const VBackgroundPatternImage &image, VAbstractPattern *doc, + QUndoCommand *parent) + : VUndoCommand(QDomElement(), doc, parent), + m_image(image) +{ + setText(tr("add background image")); +} + +//--------------------------------------------------------------------------------------------------------------------- +void AddBackgroundImage::undo() +{ + qCDebug(vUndo, "Undo."); + + doc->DeleteBackgroundImage(m_image.Id()); + emit DeleteItem(m_image.Id()); +} + +//--------------------------------------------------------------------------------------------------------------------- +void AddBackgroundImage::redo() +{ + qCDebug(vUndo, "Redo."); + + // Find and remove if already exists + doc->DeleteBackgroundImage(m_image.Id()); + + doc->SaveBackgroundImage(m_image); + emit AddItem(m_image.Id()); +} diff --git a/src/libs/vtools/undocommands/image/addbackgroundimage.h b/src/libs/vtools/undocommands/image/addbackgroundimage.h new file mode 100644 index 000000000..979e43e14 --- /dev/null +++ b/src/libs/vtools/undocommands/image/addbackgroundimage.h @@ -0,0 +1,54 @@ +/************************************************************************ + ** + ** @file addbackgroundimage.h + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ +#ifndef ADDBACKGROUNDIMAGE_H +#define ADDBACKGROUNDIMAGE_H + +#include "../vundocommand.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 AddBackgroundImage : public VUndoCommand +{ + Q_OBJECT +public: + AddBackgroundImage(const VBackgroundPatternImage& image, VAbstractPattern *doc, QUndoCommand *parent = nullptr); + ~AddBackgroundImage() override =default; + void undo() override; + void redo() override; +signals: + void AddItem(const QUuid &id); + void DeleteItem(const QUuid &id); +private: + Q_DISABLE_COPY_MOVE(AddBackgroundImage) + VBackgroundPatternImage m_image; +}; + +#endif // ADDBACKGROUNDIMAGE_H diff --git a/src/libs/vtools/undocommands/image/deletebackgroundimage.cpp b/src/libs/vtools/undocommands/image/deletebackgroundimage.cpp new file mode 100644 index 000000000..14517493a --- /dev/null +++ b/src/libs/vtools/undocommands/image/deletebackgroundimage.cpp @@ -0,0 +1,78 @@ +/************************************************************************ + ** + ** @file deletebackgroundimage.cpp + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ +#include "deletebackgroundimage.h" + +//--------------------------------------------------------------------------------------------------------------------- +DeleteBackgroundImage::DeleteBackgroundImage(const VBackgroundPatternImage &image, VAbstractPattern *doc, + QUndoCommand *parent) + : VUndoCommand(QDomElement(), doc, parent), + m_image(image) +{ + setText(tr("delete background image")); + + QVector allImages = doc->GetBackgroundImages(); + + for (int i = 0; i < allImages.size(); ++i) + { + if (allImages.at(i).Id() == image.Id()) + { + m_index = i; + break; + } + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void DeleteBackgroundImage::undo() +{ + qCDebug(vUndo, "Undo."); + + QVector allImages = doc->GetBackgroundImages(); + + if (m_index == -1) + { + doc->SaveBackgroundImage(m_image); + } + else + { + allImages.insert(m_index, m_image); + doc->SaveBackgroundImages(allImages); + } + + emit AddItem(m_image.Id()); +} + +//--------------------------------------------------------------------------------------------------------------------- +void DeleteBackgroundImage::redo() +{ + qCDebug(vUndo, "Redo."); + + doc->DeleteBackgroundImage(m_image.Id()); + + emit DeleteItem(m_image.Id()); +} diff --git a/src/libs/vtools/undocommands/image/deletebackgroundimage.h b/src/libs/vtools/undocommands/image/deletebackgroundimage.h new file mode 100644 index 000000000..74f13a3b7 --- /dev/null +++ b/src/libs/vtools/undocommands/image/deletebackgroundimage.h @@ -0,0 +1,56 @@ +/************************************************************************ + ** + ** @file deletebackgroundimage.h + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ +#ifndef DELETEBACKGROUNDIMAGE_H +#define DELETEBACKGROUNDIMAGE_H + +#include "../vundocommand.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 DeleteBackgroundImage : public VUndoCommand +{ + Q_OBJECT +public: + DeleteBackgroundImage(const VBackgroundPatternImage& image, VAbstractPattern *doc, QUndoCommand *parent = nullptr); + ~DeleteBackgroundImage() override =default; + void undo() override; + void redo() override; +signals: + void AddItem(const QUuid &id); + void DeleteItem(const QUuid &id); +private: + Q_DISABLE_COPY_MOVE(DeleteBackgroundImage) + VBackgroundPatternImage m_image; + int m_index{-1}; +}; + +#endif // DELETEBACKGROUNDIMAGE_H diff --git a/src/libs/vtools/undocommands/image/hideallbackgroundimages.cpp b/src/libs/vtools/undocommands/image/hideallbackgroundimages.cpp new file mode 100644 index 000000000..a18443de1 --- /dev/null +++ b/src/libs/vtools/undocommands/image/hideallbackgroundimages.cpp @@ -0,0 +1,79 @@ +/************************************************************************ + ** + ** @file hideallbackgroundimages.cpp + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ +#include "hideallbackgroundimages.h" +#include "../ifc/xml/vbackgroundpatternimage.h" + +//--------------------------------------------------------------------------------------------------------------------- +HideAllBackgroundImages::HideAllBackgroundImages(bool hide, VAbstractPattern *doc, QUndoCommand *parent) + : VUndoCommand(QDomElement(), doc, parent), + m_hide(hide) +{ + if (hide) + { + setText(tr("hide all background images")); + } + else + { + setText(tr("show all background images")); + } + + QVector images = doc->GetBackgroundImages(); + + for (const auto& image : images) + { + m_oldVisibility.insert(image.Id(), image.Visible()); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void HideAllBackgroundImages::undo() +{ + QVector images = doc->GetBackgroundImages(); + + for (auto &image : images) + { + image.SetVisible(m_oldVisibility.value(image.Id(), image.Visible())); + } + + doc->SaveBackgroundImages(images); + emit doc->BackgroundImagesVisibilityChanged(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void HideAllBackgroundImages::redo() +{ + QVector images = doc->GetBackgroundImages(); + + for (auto &image : images) + { + image.SetVisible(not m_hide); + } + + doc->SaveBackgroundImages(images); + emit doc->BackgroundImagesVisibilityChanged(); +} diff --git a/src/libs/vtools/undocommands/image/hideallbackgroundimages.h b/src/libs/vtools/undocommands/image/hideallbackgroundimages.h new file mode 100644 index 000000000..17ddd044a --- /dev/null +++ b/src/libs/vtools/undocommands/image/hideallbackgroundimages.h @@ -0,0 +1,51 @@ +/************************************************************************ + ** + ** @file hideallbackgroundimages.h + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ +#ifndef HIDEALLBACKGROUNDIMAGES_H +#define HIDEALLBACKGROUNDIMAGES_H + +#include "../vundocommand.h" + +#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0) +#include "../vmisc/defglobal.h" +#endif // QT_VERSION < QT_VERSION_CHECK(5, 13, 0) + + +class HideAllBackgroundImages : public VUndoCommand +{ +public: + HideAllBackgroundImages(bool hide, VAbstractPattern *doc, QUndoCommand *parent = nullptr); + ~HideAllBackgroundImages() override =default; + void undo() override; + void redo() override; +private: + Q_DISABLE_COPY_MOVE(HideAllBackgroundImages) + bool m_hide; + QMap m_oldVisibility{}; +}; + +#endif // HIDEALLBACKGROUNDIMAGES_H diff --git a/src/libs/vtools/undocommands/image/hidebackgroundimage.cpp b/src/libs/vtools/undocommands/image/hidebackgroundimage.cpp new file mode 100644 index 000000000..70c8dff05 --- /dev/null +++ b/src/libs/vtools/undocommands/image/hidebackgroundimage.cpp @@ -0,0 +1,75 @@ +/************************************************************************ + ** + ** @file hidebackgroundimage.cpp + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ +#include "hidebackgroundimage.h" +#include "../ifc/xml/vbackgroundpatternimage.h" + +//--------------------------------------------------------------------------------------------------------------------- +HideBackgroundImage::HideBackgroundImage(QUuid id, bool hide, VAbstractPattern *doc, QUndoCommand *parent) + : VUndoCommand(QDomElement(), doc, parent), + m_id(id), + m_hide(hide) +{ + if (hide) + { + setText(tr("hide a background image")); + } + else + { + setText(tr("show a background image")); + } + + VBackgroundPatternImage image = doc->GetBackgroundImage(m_id); + + m_oldVisibility = image.Visible(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void HideBackgroundImage::undo() +{ + VBackgroundPatternImage image = doc->GetBackgroundImage(m_id); + + if (not image.IsNull()) + { + image.SetVisible(m_oldVisibility); + doc->SaveBackgroundImage(image); + emit doc->BackgroundImageVisibilityChanged(m_id); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void HideBackgroundImage::redo() +{ + VBackgroundPatternImage image = doc->GetBackgroundImage(m_id); + + if (not image.IsNull()) + { + image.SetVisible(not m_hide); + doc->SaveBackgroundImage(image); + emit doc->BackgroundImageVisibilityChanged(m_id); + } +} diff --git a/src/libs/vtools/undocommands/image/hidebackgroundimage.h b/src/libs/vtools/undocommands/image/hidebackgroundimage.h new file mode 100644 index 000000000..b363bb848 --- /dev/null +++ b/src/libs/vtools/undocommands/image/hidebackgroundimage.h @@ -0,0 +1,52 @@ +/************************************************************************ + ** + ** @file hidebackgroundimage.h + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ +#ifndef HIDEBACKGROUNDIMAGE_H +#define HIDEBACKGROUNDIMAGE_H + +#include "../vundocommand.h" + +#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0) +#include "../vmisc/defglobal.h" +#endif // QT_VERSION < QT_VERSION_CHECK(5, 13, 0) + + +class HideBackgroundImage : public VUndoCommand +{ +public: + HideBackgroundImage(QUuid id, bool hide, VAbstractPattern *doc, QUndoCommand *parent = nullptr); + ~HideBackgroundImage() override =default; + void undo() override; + void redo() override; +private: + Q_DISABLE_COPY_MOVE(HideBackgroundImage) + QUuid m_id; + bool m_hide; + bool m_oldVisibility{false}; +}; + +#endif // HIDEBACKGROUNDIMAGE_H diff --git a/src/libs/vtools/undocommands/image/holdallbackgroundimages.cpp b/src/libs/vtools/undocommands/image/holdallbackgroundimages.cpp new file mode 100644 index 000000000..12c9d47a2 --- /dev/null +++ b/src/libs/vtools/undocommands/image/holdallbackgroundimages.cpp @@ -0,0 +1,79 @@ +/************************************************************************ + ** + ** @file holdallbackgroundimages.cpp + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ +#include "holdallbackgroundimages.h" +#include "../ifc/xml/vbackgroundpatternimage.h" + +//--------------------------------------------------------------------------------------------------------------------- +HoldAllBackgroundImages::HoldAllBackgroundImages(bool hold, VAbstractPattern *doc, QUndoCommand *parent) + : VUndoCommand(QDomElement(), doc, parent), + m_hold(hold) +{ + if (hold) + { + setText(tr("hold all background images")); + } + else + { + setText(tr("unhold background images")); + } + + QVector images = doc->GetBackgroundImages(); + + for (const auto& image : images) + { + m_oldHold.insert(image.Id(), image.Hold()); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void HoldAllBackgroundImages::undo() +{ + QVector images = doc->GetBackgroundImages(); + + for (auto &image : images) + { + image.SetHold(m_oldHold.value(image.Id(), image.Hold())); + } + + doc->SaveBackgroundImages(images); + emit doc->BackgroundImagesHoldChanged(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void HoldAllBackgroundImages::redo() +{ + QVector images = doc->GetBackgroundImages(); + + for (auto &image : images) + { + image.SetHold(m_hold); + } + + doc->SaveBackgroundImages(images); + emit doc->BackgroundImagesHoldChanged(); +} diff --git a/src/libs/vtools/undocommands/image/holdallbackgroundimages.h b/src/libs/vtools/undocommands/image/holdallbackgroundimages.h new file mode 100644 index 000000000..9a3e57fce --- /dev/null +++ b/src/libs/vtools/undocommands/image/holdallbackgroundimages.h @@ -0,0 +1,50 @@ +/************************************************************************ + ** + ** @file holdallbackgroundimages.h + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ +#ifndef HOLDALLBACKGROUNDIMAGES_H +#define HOLDALLBACKGROUNDIMAGES_H + +#include "../vundocommand.h" + +#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0) +#include "../vmisc/defglobal.h" +#endif // QT_VERSION < QT_VERSION_CHECK(5, 13, 0) + +class HoldAllBackgroundImages : public VUndoCommand +{ +public: + HoldAllBackgroundImages(bool hold, VAbstractPattern *doc, QUndoCommand *parent = nullptr); + ~HoldAllBackgroundImages() override =default; + void undo() override; + void redo() override; +private: + Q_DISABLE_COPY_MOVE(HoldAllBackgroundImages) + bool m_hold; + QMap m_oldHold{}; +}; + +#endif // HOLDALLBACKGROUNDIMAGES_H diff --git a/src/libs/vtools/undocommands/image/holdbackgroundimage.cpp b/src/libs/vtools/undocommands/image/holdbackgroundimage.cpp new file mode 100644 index 000000000..259fabe71 --- /dev/null +++ b/src/libs/vtools/undocommands/image/holdbackgroundimage.cpp @@ -0,0 +1,75 @@ +/************************************************************************ + ** + ** @file holdbackgroundimage.cpp + ** @author Roman Telezhynskyi + ** @date 22 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 + ** 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 . + ** + *************************************************************************/ +#include "holdbackgroundimage.h" +#include "../ifc/xml/vbackgroundpatternimage.h" + +//--------------------------------------------------------------------------------------------------------------------- +HoldBackgroundImage::HoldBackgroundImage(QUuid id, bool hold, VAbstractPattern *doc, QUndoCommand *parent) + : VUndoCommand(QDomElement(), doc, parent), + m_id(id), + m_hold(hold) +{ + if (hold) + { + setText(tr("hold background image")); + } + else + { + setText(tr("unhold background image")); + } + + VBackgroundPatternImage image = doc->GetBackgroundImage(m_id); + + m_oldHold = image.Hold(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void HoldBackgroundImage::undo() +{ + VBackgroundPatternImage image = doc->GetBackgroundImage(m_id); + + if (not image.IsNull()) + { + image.SetHold(m_oldHold); + doc->SaveBackgroundImage(image); + emit doc->BackgroundImageHoldChanged(m_id); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void HoldBackgroundImage::redo() +{ + VBackgroundPatternImage image = doc->GetBackgroundImage(m_id); + + if (not image.IsNull()) + { + image.SetHold(m_hold); + doc->SaveBackgroundImage(image); + emit doc->BackgroundImageHoldChanged(m_id); + } +} diff --git a/src/libs/vtools/undocommands/image/holdbackgroundimage.h b/src/libs/vtools/undocommands/image/holdbackgroundimage.h new file mode 100644 index 000000000..56a71d00b --- /dev/null +++ b/src/libs/vtools/undocommands/image/holdbackgroundimage.h @@ -0,0 +1,52 @@ +/************************************************************************ + ** + ** @file holdbackgroundimage.h + ** @author Roman Telezhynskyi + ** @date 22 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 + ** 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 . + ** + *************************************************************************/ +#ifndef HOLDBACKGROUNDIMAGE_H +#define HOLDBACKGROUNDIMAGE_H + +#include "../vundocommand.h" + +#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0) +#include "../vmisc/defglobal.h" +#endif // QT_VERSION < QT_VERSION_CHECK(5, 13, 0) + + +class HoldBackgroundImage : public VUndoCommand +{ +public: + HoldBackgroundImage(QUuid id, bool hold, VAbstractPattern *doc, QUndoCommand *parent = nullptr); + ~HoldBackgroundImage() override =default; + void undo() override; + void redo() override; +private: + Q_DISABLE_COPY_MOVE(HoldBackgroundImage) + QUuid m_id; + bool m_hold; + bool m_oldHold{false}; +}; + +#endif // HOLDBACKGROUNDIMAGE_H diff --git a/src/libs/vtools/undocommands/image/movebackgroundimage.cpp b/src/libs/vtools/undocommands/image/movebackgroundimage.cpp new file mode 100644 index 000000000..8e4586d10 --- /dev/null +++ b/src/libs/vtools/undocommands/image/movebackgroundimage.cpp @@ -0,0 +1,126 @@ +/************************************************************************ + ** + ** @file movebackgroundimage.cpp + ** @author Roman Telezhynskyi + ** @date 18 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 + ** 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 . + ** + *************************************************************************/ +#include "movebackgroundimage.h" +#include "../ifc/xml/vbackgroundpatternimage.h" + +//--------------------------------------------------------------------------------------------------------------------- +MoveBackgroundImage::MoveBackgroundImage(QUuid id, qreal dx, qreal dy, VAbstractPattern *doc, bool allowMerge, + QUndoCommand *parent) + : VUndoCommand(QDomElement(), doc, parent), + m_id(id), + m_dx(dx), + m_dy(dy), + m_allowMerge(allowMerge) +{ + setText(tr("move background image")); + + VBackgroundPatternImage image = doc->GetBackgroundImage(m_id); + + m_oldPos = image.Matrix(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void MoveBackgroundImage::undo() +{ + VBackgroundPatternImage image = doc->GetBackgroundImage(m_id); + + if (not image.IsNull()) + { + image.SetMatrix(m_oldPos); + doc->SaveBackgroundImage(image); + emit doc->BackgroundImagePositionChanged(m_id); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void MoveBackgroundImage::redo() +{ + VBackgroundPatternImage image = doc->GetBackgroundImage(m_id); + + if (not image.IsNull()) + { + QTransform matrix = image.Matrix(); + QTransform m; + m.translate(m_dx, m_dy); + matrix *= m; + image.SetMatrix(matrix); + doc->SaveBackgroundImage(image); + emit doc->BackgroundImagePositionChanged(m_id); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +auto MoveBackgroundImage::mergeWith(const QUndoCommand *command) -> bool +{ + if (command->id() != id()) + { + return false; + } + + const auto *moveCommand = dynamic_cast(command); + SCASSERT(moveCommand != nullptr) + + if (moveCommand->ImageId() != m_id || not moveCommand->AllowMerge()) + { + return false; + } + + m_dx = moveCommand->Dx(); + m_dy = moveCommand->Dy(); + return true; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto MoveBackgroundImage::id() const -> int +{ + return static_cast(UndoCommand::MoveBackGroundImage); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto MoveBackgroundImage::ImageId() const -> QUuid +{ + return m_id; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto MoveBackgroundImage::Dx() const -> qreal +{ + return m_dx; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto MoveBackgroundImage::Dy() const -> qreal +{ + return m_dy; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto MoveBackgroundImage::AllowMerge() const -> bool +{ + return m_allowMerge; +} diff --git a/src/libs/vtools/undocommands/image/movebackgroundimage.h b/src/libs/vtools/undocommands/image/movebackgroundimage.h new file mode 100644 index 000000000..54d707bc9 --- /dev/null +++ b/src/libs/vtools/undocommands/image/movebackgroundimage.h @@ -0,0 +1,69 @@ +/************************************************************************ + ** + ** @file movebackgroundimage.h + ** @author Roman Telezhynskyi + ** @date 18 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 + ** 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 . + ** + *************************************************************************/ +#ifndef MOVEBACKGROUNDIMAGE_H +#define MOVEBACKGROUNDIMAGE_H + +#include "../vundocommand.h" + +#include +#include + +#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0) +#include "../vmisc/defglobal.h" +#endif // QT_VERSION < QT_VERSION_CHECK(5, 13, 0) + +class MoveBackgroundImage : public VUndoCommand +{ + Q_OBJECT +public: + MoveBackgroundImage(QUuid id, qreal dx, qreal dy, VAbstractPattern *doc, bool allowMerge = false, + QUndoCommand *parent = nullptr); + ~MoveBackgroundImage() override = default; + + void undo() override; + void redo() override; + // cppcheck-suppress unusedFunction + auto mergeWith(const QUndoCommand *command) -> bool override; + auto id() const -> int override; + + auto ImageId() const -> QUuid; + auto Dx() const -> qreal; + auto Dy() const -> qreal; + auto AllowMerge() const -> bool; + +private: + Q_DISABLE_COPY_MOVE(MoveBackgroundImage) + + QUuid m_id; + qreal m_dx; + qreal m_dy; + QTransform m_oldPos{}; + bool m_allowMerge; +}; + +#endif // MOVEBACKGROUNDIMAGE_H diff --git a/src/libs/vtools/undocommands/image/renamebackgroundimage.cpp b/src/libs/vtools/undocommands/image/renamebackgroundimage.cpp new file mode 100644 index 000000000..158f6437d --- /dev/null +++ b/src/libs/vtools/undocommands/image/renamebackgroundimage.cpp @@ -0,0 +1,68 @@ +/************************************************************************ + ** + ** @file renamebackgroundimage.cpp + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ +#include "renamebackgroundimage.h" +#include "../ifc/xml/vbackgroundpatternimage.h" + +//--------------------------------------------------------------------------------------------------------------------- +RenameBackgroundImage::RenameBackgroundImage(QUuid id, const QString &name, VAbstractPattern *doc, QUndoCommand *parent) + : VUndoCommand(QDomElement(), doc, parent), + m_id(id), + m_name(name) +{ + setText(tr("rename background image")); + + VBackgroundPatternImage image = doc->GetBackgroundImage(m_id); + + m_oldName = image.Name(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void RenameBackgroundImage::undo() +{ + VBackgroundPatternImage image = doc->GetBackgroundImage(m_id); + + if (not image.IsNull()) + { + image.SetName(m_oldName); + doc->SaveBackgroundImage(image); + emit doc->BackgroundImageNameChanged(m_id); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void RenameBackgroundImage::redo() +{ + VBackgroundPatternImage image = doc->GetBackgroundImage(m_id); + + if (not image.IsNull()) + { + image.SetName(m_name); + doc->SaveBackgroundImage(image); + emit doc->BackgroundImageNameChanged(m_id); + } +} diff --git a/src/libs/vtools/undocommands/image/renamebackgroundimage.h b/src/libs/vtools/undocommands/image/renamebackgroundimage.h new file mode 100644 index 000000000..fa7808dde --- /dev/null +++ b/src/libs/vtools/undocommands/image/renamebackgroundimage.h @@ -0,0 +1,52 @@ +/************************************************************************ + ** + ** @file renamebackgroundimage.h + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ +#ifndef RENAMEBACKGROUNDIMAGE_H +#define RENAMEBACKGROUNDIMAGE_H + +#include "../vundocommand.h" + +#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0) +#include "../vmisc/defglobal.h" +#endif // QT_VERSION < QT_VERSION_CHECK(5, 13, 0) + + +class RenameBackgroundImage : public VUndoCommand +{ +public: + RenameBackgroundImage(QUuid id, const QString &name, VAbstractPattern *doc, QUndoCommand *parent = nullptr); + ~RenameBackgroundImage() override =default; + void undo() override; + void redo() override; +private: + Q_DISABLE_COPY_MOVE(RenameBackgroundImage) + QUuid m_id; + QString m_name; + QString m_oldName{}; +}; + +#endif // RENAMEBACKGROUNDIMAGE_H diff --git a/src/libs/vtools/undocommands/image/resetbackgroundimage.cpp b/src/libs/vtools/undocommands/image/resetbackgroundimage.cpp new file mode 100644 index 000000000..54fca82dc --- /dev/null +++ b/src/libs/vtools/undocommands/image/resetbackgroundimage.cpp @@ -0,0 +1,66 @@ +/************************************************************************ + ** + ** @file resetbackgroundimage.cpp + ** @author Roman Telezhynskyi + ** @date 28 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 + ** 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 . + ** + *************************************************************************/ +#include "resetbackgroundimage.h" +#include "../ifc/xml/vbackgroundpatternimage.h" + +//--------------------------------------------------------------------------------------------------------------------- +ResetBackgroundImage::ResetBackgroundImage(QUuid id, VAbstractPattern *doc, QUndoCommand *parent) + : VUndoCommand(QDomElement(), doc, parent), + m_id(id) +{ + setText(tr("reset background image transformation")); + + VBackgroundPatternImage image = doc->GetBackgroundImage(m_id); + m_oldMatrix = image.Matrix(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void ResetBackgroundImage::undo() +{ + VBackgroundPatternImage image = doc->GetBackgroundImage(m_id); + + if (not image.IsNull()) + { + image.SetMatrix(m_oldMatrix); + doc->SaveBackgroundImage(image); + emit doc->BackgroundImageTransformationChanged(m_id); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void ResetBackgroundImage::redo() +{ + VBackgroundPatternImage image = doc->GetBackgroundImage(m_id); + + if (not image.IsNull()) + { + image.SetMatrix(QTransform()); + doc->SaveBackgroundImage(image); + emit doc->BackgroundImageTransformationChanged(m_id); + } +} diff --git a/src/libs/vtools/undocommands/image/resetbackgroundimage.h b/src/libs/vtools/undocommands/image/resetbackgroundimage.h new file mode 100644 index 000000000..341983a77 --- /dev/null +++ b/src/libs/vtools/undocommands/image/resetbackgroundimage.h @@ -0,0 +1,56 @@ +/************************************************************************ + ** + ** @file resetbackgroundimage.h + ** @author Roman Telezhynskyi + ** @date 28 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 + ** 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 . + ** + *************************************************************************/ +#ifndef RESETBACKGROUNDIMAGE_H +#define RESETBACKGROUNDIMAGE_H + +#include "../vundocommand.h" + +#include +#include + +#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0) +#include "../vmisc/defglobal.h" +#endif // QT_VERSION < QT_VERSION_CHECK(5, 13, 0) + +class ResetBackgroundImage : public VUndoCommand +{ +public: + ResetBackgroundImage(QUuid id, VAbstractPattern *doc, QUndoCommand *parent = nullptr); + ~ResetBackgroundImage() override = default; + + void undo() override; + void redo() override; + +private: + Q_DISABLE_COPY_MOVE(ResetBackgroundImage) + + QUuid m_id; + QTransform m_oldMatrix{}; +}; + +#endif // RESETBACKGROUNDIMAGE_H diff --git a/src/libs/vtools/undocommands/image/rotatebackgroundimage.cpp b/src/libs/vtools/undocommands/image/rotatebackgroundimage.cpp new file mode 100644 index 000000000..2f8923921 --- /dev/null +++ b/src/libs/vtools/undocommands/image/rotatebackgroundimage.cpp @@ -0,0 +1,114 @@ +/************************************************************************ + ** + ** @file rotatebackgroundimage.cpp + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ +#include "rotatebackgroundimage.h" +#include "../ifc/xml/vbackgroundpatternimage.h" + +//--------------------------------------------------------------------------------------------------------------------- +RotateBackgroundImage::RotateBackgroundImage(QUuid id, const QTransform &matrix, VAbstractPattern *doc, bool allowMerge, + QUndoCommand *parent) + : VUndoCommand(QDomElement(), doc, parent), + m_id(id), + m_matrix(matrix), + m_allowMerge(allowMerge) +{ + setText(tr("rotate background image")); + + VBackgroundPatternImage image = doc->GetBackgroundImage(m_id); + + m_oldMatrix = image.Matrix(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void RotateBackgroundImage::undo() +{ + VBackgroundPatternImage image = doc->GetBackgroundImage(m_id); + + if (not image.IsNull()) + { + image.SetMatrix(m_oldMatrix); + doc->SaveBackgroundImage(image); + emit doc->BackgroundImageTransformationChanged(m_id); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void RotateBackgroundImage::redo() +{ + VBackgroundPatternImage image = doc->GetBackgroundImage(m_id); + + if (not image.IsNull()) + { + image.SetMatrix(m_matrix); + doc->SaveBackgroundImage(image); + emit doc->BackgroundImageTransformationChanged(m_id); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +bool RotateBackgroundImage::mergeWith(const QUndoCommand *command) +{ + if (command->id() != id()) + { + return false; + } + + const auto *moveCommand = dynamic_cast(command); + SCASSERT(moveCommand != nullptr) + + if (moveCommand->ImageId() != m_id || not moveCommand->AllowMerge()) + { + return false; + } + + m_matrix = moveCommand->Matrix(); + return true; +} + +//--------------------------------------------------------------------------------------------------------------------- +int RotateBackgroundImage::id() const +{ + return static_cast(UndoCommand::RotateBackGroundImage); +} + +//--------------------------------------------------------------------------------------------------------------------- +QUuid RotateBackgroundImage::ImageId() const +{ + return m_id; +} + +//--------------------------------------------------------------------------------------------------------------------- +QTransform RotateBackgroundImage::Matrix() const +{ + return m_matrix; +} + +//--------------------------------------------------------------------------------------------------------------------- +bool RotateBackgroundImage::AllowMerge() const +{ + return m_allowMerge; +} diff --git a/src/libs/vtools/undocommands/image/rotatebackgroundimage.h b/src/libs/vtools/undocommands/image/rotatebackgroundimage.h new file mode 100644 index 000000000..3536b9d59 --- /dev/null +++ b/src/libs/vtools/undocommands/image/rotatebackgroundimage.h @@ -0,0 +1,67 @@ +/************************************************************************ + ** + ** @file rotatebackgroundimage.h + ** @author Roman Telezhynskyi + ** @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 + ** 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 . + ** + *************************************************************************/ +#ifndef ROTATEBACKGROUNDIMAGE_H +#define ROTATEBACKGROUNDIMAGE_H + +#include "../vundocommand.h" + +#include +#include + +#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0) +#include "../vmisc/defglobal.h" +#endif // QT_VERSION < QT_VERSION_CHECK(5, 13, 0) + + +class RotateBackgroundImage : public VUndoCommand +{ +public: + RotateBackgroundImage(QUuid id, const QTransform &matrix, VAbstractPattern *doc, bool allowMerge = false, + QUndoCommand *parent = nullptr); + ~RotateBackgroundImage() override = default; + + void undo() override; + void redo() override; + // cppcheck-suppress unusedFunction + auto mergeWith(const QUndoCommand *command) -> bool override; + auto id() const -> int override; + + auto ImageId() const -> QUuid; + auto Matrix() const -> QTransform; + auto AllowMerge() const -> bool; + +private: + Q_DISABLE_COPY_MOVE(RotateBackgroundImage) + + QUuid m_id; + QTransform m_matrix; + QTransform m_oldMatrix{}; + bool m_allowMerge; +}; + +#endif // ROTATEBACKGROUNDIMAGE_H diff --git a/src/libs/vtools/undocommands/image/scalebackgroundimage.cpp b/src/libs/vtools/undocommands/image/scalebackgroundimage.cpp new file mode 100644 index 000000000..f41d61980 --- /dev/null +++ b/src/libs/vtools/undocommands/image/scalebackgroundimage.cpp @@ -0,0 +1,114 @@ +/************************************************************************ + ** + ** @file scalebackgroundimage.cpp + ** @author Roman Telezhynskyi + ** @date 18 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 + ** 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 . + ** + *************************************************************************/ +#include "scalebackgroundimage.h" +#include "../ifc/xml/vbackgroundpatternimage.h" + +//--------------------------------------------------------------------------------------------------------------------- +ScaleBackgroundImage::ScaleBackgroundImage(QUuid id, const QTransform &matrix, VAbstractPattern *doc, bool allowMerge, + QUndoCommand *parent) + : VUndoCommand(QDomElement(), doc, parent), + m_id(id), + m_matrix(matrix), + m_allowMerge(allowMerge) +{ + setText(tr("scale background image")); + + VBackgroundPatternImage image = doc->GetBackgroundImage(m_id); + + m_oldMatrix = image.Matrix(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void ScaleBackgroundImage::undo() +{ + VBackgroundPatternImage image = doc->GetBackgroundImage(m_id); + + if (not image.IsNull()) + { + image.SetMatrix(m_oldMatrix); + doc->SaveBackgroundImage(image); + emit doc->BackgroundImageTransformationChanged(m_id); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void ScaleBackgroundImage::redo() +{ + VBackgroundPatternImage image = doc->GetBackgroundImage(m_id); + + if (not image.IsNull()) + { + image.SetMatrix(m_matrix); + doc->SaveBackgroundImage(image); + emit doc->BackgroundImageTransformationChanged(m_id); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +bool ScaleBackgroundImage::mergeWith(const QUndoCommand *command) +{ + if (command->id() != id()) + { + return false; + } + + const auto *moveCommand = dynamic_cast(command); + SCASSERT(moveCommand != nullptr) + + if (moveCommand->ImageId() != m_id || not moveCommand->AllowMerge()) + { + return false; + } + + m_matrix = moveCommand->Matrix(); + return true; +} + +//--------------------------------------------------------------------------------------------------------------------- +int ScaleBackgroundImage::id() const +{ + return static_cast(UndoCommand::ScaleBackGroundImage); +} + +//--------------------------------------------------------------------------------------------------------------------- +QUuid ScaleBackgroundImage::ImageId() const +{ + return m_id; +} + +//--------------------------------------------------------------------------------------------------------------------- +QTransform ScaleBackgroundImage::Matrix() const +{ + return m_matrix; +} + +//--------------------------------------------------------------------------------------------------------------------- +bool ScaleBackgroundImage::AllowMerge() const +{ + return m_allowMerge; +} diff --git a/src/libs/vtools/undocommands/image/scalebackgroundimage.h b/src/libs/vtools/undocommands/image/scalebackgroundimage.h new file mode 100644 index 000000000..66b928a99 --- /dev/null +++ b/src/libs/vtools/undocommands/image/scalebackgroundimage.h @@ -0,0 +1,68 @@ +/************************************************************************ + ** + ** @file scalebackgroundimage.h + ** @author Roman Telezhynskyi + ** @date 18 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 + ** 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 . + ** + *************************************************************************/ +#ifndef SCALEBACKGROUNDIMAGE_H +#define SCALEBACKGROUNDIMAGE_H + +#include "../vundocommand.h" + +#include +#include + +#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0) +#include "../vmisc/defglobal.h" +#endif // QT_VERSION < QT_VERSION_CHECK(5, 13, 0) + + +class ScaleBackgroundImage : public VUndoCommand +{ + Q_OBJECT +public: + ScaleBackgroundImage(QUuid id, const QTransform &matrix, VAbstractPattern *doc, bool allowMerge = false, + QUndoCommand *parent = nullptr); + ~ScaleBackgroundImage() override = default; + + void undo() override; + void redo() override; + // cppcheck-suppress unusedFunction + auto mergeWith(const QUndoCommand *command) -> bool override; + auto id() const -> int override; + + auto ImageId() const -> QUuid; + auto Matrix() const -> QTransform; + auto AllowMerge() const -> bool; + +private: + Q_DISABLE_COPY_MOVE(ScaleBackgroundImage) + + QUuid m_id; + QTransform m_matrix; + QTransform m_oldMatrix{}; + bool m_allowMerge; +}; + +#endif // SCALEBACKGROUNDIMAGE_H diff --git a/src/libs/vtools/undocommands/image/zvaluemovebackgroundimage.cpp b/src/libs/vtools/undocommands/image/zvaluemovebackgroundimage.cpp new file mode 100644 index 000000000..2d9612330 --- /dev/null +++ b/src/libs/vtools/undocommands/image/zvaluemovebackgroundimage.cpp @@ -0,0 +1,158 @@ +/************************************************************************ + ** + ** @file zvaluemovebackgroundimage.cpp + ** @author Roman Telezhynskyi + ** @date 27 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 + ** 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 . + ** + *************************************************************************/ +#include "zvaluemovebackgroundimage.h" +#include "../ifc/xml/vbackgroundpatternimage.h" + +namespace +{ +//--------------------------------------------------------------------------------------------------------------------- +auto CorrectedZValues(const QList> &order) -> QHash +{ + QHash correctedZValues; + + for (int i = 0; i < order.size(); ++i) + { + const QVector &level = order.at(i); + for (const auto &imgId : level) + { + correctedZValues.insert(imgId, i); + } + } + + return correctedZValues; +} +} // namespace + +//--------------------------------------------------------------------------------------------------------------------- +ZValueMoveBackgroundImage::ZValueMoveBackgroundImage(QUuid id, ZValueMove move, VAbstractPattern *doc, + QUndoCommand *parent) + : VUndoCommand(QDomElement(), doc, parent), + m_id(id), + m_move(move) +{ + setText(tr("z value move a background image")); + + QVector images = doc->GetBackgroundImages(); + + for (const auto &image: images) + { + m_oldValues.insert(image.Id(), image.ZValue()); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void ZValueMoveBackgroundImage::undo() +{ + QVector images = doc->GetBackgroundImages(); + + for (auto &image: images) + { + image.SetZValue(m_oldValues.value(image.Id(), image.ZValue())); + } + + doc->SaveBackgroundImages(images); + emit doc->BackgroundImagesZValueChanged(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void ZValueMoveBackgroundImage::redo() +{ + QVector images = doc->GetBackgroundImages(); + + auto Levels = [this](const QVector &images, bool skip) + { + QMap> levels; + + for (const auto &image: images) + { + if (skip && image.Id() == m_id) + { + continue; + } + + if (levels.contains(image.ZValue())) + { + QVector lavel_images = levels.value(image.ZValue()); + lavel_images.append(image.Id()); + levels[image.ZValue()] = lavel_images; + } + else + { + levels[image.ZValue()] = {image.Id()}; + } + } + + return levels.values(); + }; + + QList> order; + + if (m_move == ZValueMove::Top) + { + order = Levels(images, true); + order.prepend({m_id}); + } + else if (m_move == ZValueMove::Up) + { + for (auto &image: images) + { + if (image.Id() != m_id) + { + image.SetZValue(image.ZValue() + 1); + } + } + + order = Levels(images, false); + } + else if (m_move == ZValueMove::Down) + { + for (auto &image: images) + { + if (image.Id() != m_id) + { + image.SetZValue(image.ZValue() - 1); + } + } + + order = Levels(images, false); + } + else if (m_move == ZValueMove::Bottom) + { + order = Levels(images, true); + order.append({m_id}); + } + + QHash correctedZValues = CorrectedZValues(order); + for (auto &image: images) + { + image.SetZValue(correctedZValues.value(image.Id(), image.ZValue())); + } + + doc->SaveBackgroundImages(images); + emit doc->BackgroundImagesZValueChanged(); +} diff --git a/src/libs/vtools/undocommands/image/zvaluemovebackgroundimage.h b/src/libs/vtools/undocommands/image/zvaluemovebackgroundimage.h new file mode 100644 index 000000000..91d98b945 --- /dev/null +++ b/src/libs/vtools/undocommands/image/zvaluemovebackgroundimage.h @@ -0,0 +1,59 @@ +/************************************************************************ + ** + ** @file zvaluemovebackgroundimage.h + ** @author Roman Telezhynskyi + ** @date 27 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 + ** 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 . + ** + *************************************************************************/ +#ifndef ZVALUEMOVEBACKGROUNDIMAGE_H +#define ZVALUEMOVEBACKGROUNDIMAGE_H + +#include "../vundocommand.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 ZValueMove +{ + Top, + Up, + Down, + Bottom +}; + +class ZValueMoveBackgroundImage : public VUndoCommand +{ +public: + ZValueMoveBackgroundImage(QUuid id, ZValueMove move, VAbstractPattern *doc, QUndoCommand *parent = nullptr); + ~ZValueMoveBackgroundImage() override =default; + void undo() override; + void redo() override; +private: + Q_DISABLE_COPY_MOVE(ZValueMoveBackgroundImage) + QUuid m_id; + ZValueMove m_move; + QHash m_oldValues{}; +}; + +#endif // ZVALUEMOVEBACKGROUNDIMAGE_H diff --git a/src/libs/vtools/undocommands/undocommands.pri b/src/libs/vtools/undocommands/undocommands.pri index 37d8a34b6..98385852a 100644 --- a/src/libs/vtools/undocommands/undocommands.pri +++ b/src/libs/vtools/undocommands/undocommands.pri @@ -4,6 +4,18 @@ HEADERS += \ $$PWD/addtocalc.h \ $$PWD/addpatternpiece.h \ + $$PWD/image/addbackgroundimage.h \ + $$PWD/image/deletebackgroundimage.h \ + $$PWD/image/hideallbackgroundimages.h \ + $$PWD/image/hidebackgroundimage.h \ + $$PWD/image/holdallbackgroundimages.h \ + $$PWD/image/holdbackgroundimage.h \ + $$PWD/image/movebackgroundimage.h \ + $$PWD/image/renamebackgroundimage.h \ + $$PWD/image/resetbackgroundimage.h \ + $$PWD/image/rotatebackgroundimage.h \ + $$PWD/image/scalebackgroundimage.h \ + $$PWD/image/zvaluemovebackgroundimage.h \ $$PWD/movespoint.h \ $$PWD/movespline.h \ $$PWD/movesplinepath.h \ @@ -31,6 +43,18 @@ HEADERS += \ SOURCES += \ $$PWD/addtocalc.cpp \ $$PWD/addpatternpiece.cpp \ + $$PWD/image/addbackgroundimage.cpp \ + $$PWD/image/deletebackgroundimage.cpp \ + $$PWD/image/hideallbackgroundimages.cpp \ + $$PWD/image/hidebackgroundimage.cpp \ + $$PWD/image/holdallbackgroundimages.cpp \ + $$PWD/image/holdbackgroundimage.cpp \ + $$PWD/image/movebackgroundimage.cpp \ + $$PWD/image/renamebackgroundimage.cpp \ + $$PWD/image/resetbackgroundimage.cpp \ + $$PWD/image/rotatebackgroundimage.cpp \ + $$PWD/image/scalebackgroundimage.cpp \ + $$PWD/image/zvaluemovebackgroundimage.cpp \ $$PWD/movespoint.cpp \ $$PWD/movespline.cpp \ $$PWD/movesplinepath.cpp \ diff --git a/src/libs/vtools/undocommands/vundocommand.h b/src/libs/vtools/undocommands/vundocommand.h index dcb9b7461..3ef89afee 100644 --- a/src/libs/vtools/undocommands/vundocommand.h +++ b/src/libs/vtools/undocommands/vundocommand.h @@ -60,7 +60,10 @@ enum class UndoCommand: qint8 RenamePP, MoveLabel, MoveDoubleLabel, - RotationMoveLabel + RotationMoveLabel, + MoveBackGroundImage, + ScaleBackGroundImage, + RotateBackGroundImage }; class VPattern; diff --git a/src/libs/vwidgets/vmaingraphicsscene.cpp b/src/libs/vwidgets/vmaingraphicsscene.cpp index e15d474e2..95ba2de12 100644 --- a/src/libs/vwidgets/vmaingraphicsscene.cpp +++ b/src/libs/vwidgets/vmaingraphicsscene.cpp @@ -44,6 +44,7 @@ #include "global.h" #include "../vmisc/vabstractapplication.h" + //--------------------------------------------------------------------------------------------------------------------- /** * @brief VMainGraphicsScene default constructor. @@ -98,9 +99,7 @@ void VMainGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event) QGraphicsScene::mousePressEvent(event); - QTransform t; - QGraphicsItem* pItem = itemAt(event->scenePos(), t); - emit ItemClicked(pItem); + emit ItemByMousePress(itemAt(event->scenePos(), {})); } //--------------------------------------------------------------------------------------------------------------------- @@ -109,10 +108,23 @@ void VMainGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) if (event->button() == Qt::LeftButton && event->type() != QEvent::GraphicsSceneMouseDoubleClick) { emit MouseLeftReleased(); + emit ItemByMouseRelease(itemAt(event->scenePos(), {})); } QGraphicsScene::mouseReleaseEvent(event); } +//--------------------------------------------------------------------------------------------------------------------- +void VMainGraphicsScene::SetAcceptDrop(bool newAcceptDrop) +{ + m_acceptDrop = newAcceptDrop; +} + +//--------------------------------------------------------------------------------------------------------------------- +bool VMainGraphicsScene::AcceptDrop() const +{ + return m_acceptDrop; +} + //--------------------------------------------------------------------------------------------------------------------- bool VMainGraphicsScene::IsNonInteractive() const { @@ -138,10 +150,10 @@ void VMainGraphicsScene::InitOrigins() { // X axis const QLineF lineX(QPointF(25, 0), QPointF(-5, 0)); - QGraphicsLineItem *xLine1 = new QGraphicsLineItem(lineX); + auto *xLine1 = new QGraphicsLineItem(lineX); xLine1->setPen(originsPen); xLine1->setFlag(QGraphicsItem::ItemIgnoresTransformations); - xLine1->setZValue(-1.0); + xLine1->setZValue(-0.5); addItem(xLine1); origins.append(xLine1); @@ -149,10 +161,10 @@ void VMainGraphicsScene::InitOrigins() QLineF arrowLeftLine = lineX; arrowLeftLine.setAngle(arrowLeftLine.angle()-arrowAngle); arrowLeftLine.setLength(arrowLength); - QGraphicsLineItem *xLine2 = new QGraphicsLineItem(arrowLeftLine); + auto *xLine2 = new QGraphicsLineItem(arrowLeftLine); xLine2->setPen(originsPen); xLine2->setFlag(QGraphicsItem::ItemIgnoresTransformations); - xLine2->setZValue(-1.0); + xLine2->setZValue(-0.5); addItem(xLine2); origins.append(xLine2); @@ -160,18 +172,18 @@ void VMainGraphicsScene::InitOrigins() QLineF arrowRightLine = lineX; arrowRightLine.setAngle(arrowRightLine.angle()+arrowAngle); arrowRightLine.setLength(arrowLength); - QGraphicsLineItem *xLine3 = new QGraphicsLineItem(arrowRightLine); + auto *xLine3 = new QGraphicsLineItem(arrowRightLine); xLine3->setPen(originsPen); xLine3->setFlag(QGraphicsItem::ItemIgnoresTransformations); - xLine3->setZValue(-1.0); + xLine3->setZValue(-0.5); addItem(xLine3); origins.append(xLine3); // X axis text - QGraphicsSimpleTextItem *xOrigin = new QGraphicsSimpleTextItem(QStringLiteral("X"), xLine1); + auto *xOrigin = new QGraphicsSimpleTextItem(QStringLiteral("X"), xLine1); xOrigin->setBrush(axisTextBrush); xOrigin->setFlag(QGraphicsItem::ItemIgnoresTransformations); - xOrigin->setZValue(-1.0); + xOrigin->setZValue(-0.5); xOrigin->setPos(30, -(xOrigin->boundingRect().height()/2)); origins.append(xOrigin); } @@ -179,10 +191,10 @@ void VMainGraphicsScene::InitOrigins() { // Y axis const QLineF lineY(QPointF(0, 25), QPointF(0, -5)); - QGraphicsLineItem *yLine1 = new QGraphicsLineItem(lineY); + auto *yLine1 = new QGraphicsLineItem(lineY); yLine1->setPen(originsPen); yLine1->setFlag(QGraphicsItem::ItemIgnoresTransformations); - yLine1->setZValue(-1.0); + yLine1->setZValue(-0.5); addItem(yLine1); origins.append(yLine1); @@ -190,10 +202,10 @@ void VMainGraphicsScene::InitOrigins() QLineF arrowLeftLine = lineY; arrowLeftLine.setAngle(arrowLeftLine.angle()-arrowAngle); arrowLeftLine.setLength(arrowLength); - QGraphicsLineItem *yLine2 = new QGraphicsLineItem(arrowLeftLine); + auto *yLine2 = new QGraphicsLineItem(arrowLeftLine); yLine2->setPen(originsPen); yLine2->setFlag(QGraphicsItem::ItemIgnoresTransformations); - yLine2->setZValue(-1.0); + yLine2->setZValue(-0.5); addItem(yLine2); origins.append(yLine2); @@ -201,18 +213,18 @@ void VMainGraphicsScene::InitOrigins() QLineF arrowRightLine = lineY; arrowRightLine.setAngle(arrowRightLine.angle()+arrowAngle); arrowRightLine.setLength(arrowLength); - QGraphicsLineItem *yLine3 = new QGraphicsLineItem(arrowRightLine); + auto *yLine3 = new QGraphicsLineItem(arrowRightLine); yLine3->setPen(originsPen); yLine3->setFlag(QGraphicsItem::ItemIgnoresTransformations); - yLine3->setZValue(-1.0); + yLine3->setZValue(-0.5); addItem(yLine3); origins.append(yLine3); // Y axis text - QGraphicsSimpleTextItem *yOrigin = new QGraphicsSimpleTextItem(QStringLiteral("Y"), yLine1); + auto *yOrigin = new QGraphicsSimpleTextItem(QStringLiteral("Y"), yLine1); yOrigin->setBrush(axisTextBrush); yOrigin->setFlag(QGraphicsItem::ItemIgnoresTransformations); - yOrigin->setZValue(-1.0); + yOrigin->setZValue(-0.5); yOrigin->setPos(-(yOrigin->boundingRect().width()/2), 30); origins.append(yOrigin); } diff --git a/src/libs/vwidgets/vmaingraphicsscene.h b/src/libs/vwidgets/vmaingraphicsscene.h index aced01546..ede6ec022 100644 --- a/src/libs/vwidgets/vmaingraphicsscene.h +++ b/src/libs/vwidgets/vmaingraphicsscene.h @@ -67,6 +67,9 @@ public: bool IsNonInteractive() const; void SetNonInteractive(bool nonInteractive); + void SetAcceptDrop(bool newAcceptDrop); + auto AcceptDrop() const -> bool; + public slots: void ChoosedItem(quint32 id, const SceneObject &type); void SelectedItem(bool selected, quint32 object, quint32 tool); @@ -110,7 +113,9 @@ signals: void MouseLeftPressed(); void MouseLeftReleased(); - void ItemClicked(QGraphicsItem* pItem); + void ItemByMousePress(QGraphicsItem* pItem); + void ItemByMouseRelease(QGraphicsItem* pItem); + void AddBackgroundImage(const QPointF &pos, const QString &fileName); /** * @brief ChoosedObject send option choosed object. @@ -165,6 +170,8 @@ private: /** @brief m_nonInteractive all item on scene in non interactive. */ bool m_nonInteractive{false}; + + bool m_acceptDrop{false}; }; //--------------------------------------------------------------------------------------------------------------------- diff --git a/src/libs/vwidgets/vmaingraphicsview.cpp b/src/libs/vwidgets/vmaingraphicsview.cpp index d170bae74..daacb96ab 100644 --- a/src/libs/vwidgets/vmaingraphicsview.cpp +++ b/src/libs/vwidgets/vmaingraphicsview.cpp @@ -49,6 +49,8 @@ #include #include #include +#include +#include #include "../vmisc/def.h" #include "../vmisc/vmath.h" @@ -59,6 +61,7 @@ #include "../vmisc/vcommonsettings.h" #include "vabstractmainwindow.h" #include "global.h" +#include "../ifc/xml/utils.h" const qreal maxSceneSize = ((20.0 * 1000.0) / 25.4) * PrintDPI; // 20 meters in pixels @@ -430,6 +433,8 @@ VMainGraphicsView::VMainGraphicsView(QWidget *parent) m_oldCursor(), m_currentCursor(Qt::ArrowCursor) { + setAcceptDrops(true); + VCommonSettings *settings = qobject_cast(VAbstractApplication::VApp()->Settings()); if (settings && settings->IsOpenGLRender()) { @@ -653,6 +658,67 @@ void VMainGraphicsView::mouseDoubleClickEvent(QMouseEvent *event) QGraphicsView::mouseDoubleClickEvent(event); } +//--------------------------------------------------------------------------------------------------------------------- +void VMainGraphicsView::dragEnterEvent(QDragEnterEvent *event) +{ + const QMimeData *mime = event->mimeData(); + auto *currentScene = qobject_cast(scene()); + if (currentScene != nullptr && currentScene->AcceptDrop() && mime != nullptr && mime->hasText()) + { + QUrl urlPath(mime->text().simplified()); + if (urlPath.isLocalFile()) + { + const QString fileName = urlPath.toLocalFile(); + QFileInfo f(fileName); + if (f.exists() && IsMimeTypeImage(QMimeDatabase().mimeTypeForFile(fileName))) + { + event->acceptProposedAction(); + } + } + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VMainGraphicsView::dragMoveEvent(QDragMoveEvent *event) +{ + const QMimeData *mime = event->mimeData(); + auto *currentScene = qobject_cast(scene()); + if (currentScene != nullptr && currentScene->AcceptDrop() && mime != nullptr && mime->hasText()) + { + QUrl urlPath(mime->text().simplified()); + if (urlPath.isLocalFile()) + { + const QString fileName = urlPath.toLocalFile(); + QFileInfo f(fileName); + if (f.exists() && IsMimeTypeImage(QMimeDatabase().mimeTypeForFile(fileName))) + { + event->acceptProposedAction(); + } + } + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VMainGraphicsView::dropEvent(QDropEvent *event) +{ + const QMimeData *mime = event->mimeData(); + auto *currentScene = qobject_cast(scene()); + if (currentScene != nullptr && currentScene->AcceptDrop() && mime != nullptr && mime->hasText()) + { + QUrl urlPath(mime->text().simplified()); + if (urlPath.isLocalFile()) + { + const QString fileName = urlPath.toLocalFile(); + QFileInfo f(fileName); + if (f.exists() && IsMimeTypeImage(QMimeDatabase().mimeTypeForFile(fileName))) + { + emit currentScene->AddBackgroundImage(mapToScene(event->pos()), fileName); + event->acceptProposedAction(); + } + } + } +} + //--------------------------------------------------------------------------------------------------------------------- qreal VMainGraphicsView::MinScale() { diff --git a/src/libs/vwidgets/vmaingraphicsview.h b/src/libs/vwidgets/vmaingraphicsview.h index f6db798d2..d5155e2a2 100644 --- a/src/libs/vwidgets/vmaingraphicsview.h +++ b/src/libs/vwidgets/vmaingraphicsview.h @@ -158,10 +158,13 @@ public slots: void ZoomFitBest(); void ResetScrollingAnimation(); protected: - virtual void mousePressEvent(QMouseEvent *event) override; - virtual void mouseMoveEvent(QMouseEvent *event) override; - virtual void mouseReleaseEvent(QMouseEvent *event) override; - virtual void mouseDoubleClickEvent(QMouseEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void mouseDoubleClickEvent(QMouseEvent *event) override; + void dragEnterEvent(QDragEnterEvent *event) override; + void dragMoveEvent(QDragMoveEvent *event) override; + void dropEvent(QDropEvent *event) override; private: Q_DISABLE_COPY(VMainGraphicsView) GraphicsViewZoom* zoom;