From 9ad3f942650bfd89171f5195df555689cdb25980 Mon Sep 17 00:00:00 2001 From: Paddle Date: Thu, 6 Apr 2023 22:35:49 +0200 Subject: [PATCH] Image: Merge taskboxes into one 'Image plane Settings' - Allow user to position the image with a X / Y distance. - Allow user to rotate the image on its plane. - Adds Transparency. - Image sizes change from PX to System unit as PX don't make sense for the user. --- src/Gui/CMakeLists.txt | 10 +- .../{TaskImageScale.cpp => TaskImage.cpp} | 291 +++++++++++++-- .../{TaskImageScale.h => TaskImage.h} | 55 ++- src/Gui/TaskView/TaskImage.ui | 346 ++++++++++++++++++ src/Gui/TaskView/TaskImageScale.ui | 184 ---------- src/Gui/ViewProviderImagePlane.cpp | 10 +- 6 files changed, 654 insertions(+), 242 deletions(-) rename src/Gui/TaskView/{TaskImageScale.cpp => TaskImage.cpp} (54%) rename src/Gui/TaskView/{TaskImageScale.h => TaskImage.h} (75%) create mode 100644 src/Gui/TaskView/TaskImage.ui delete mode 100644 src/Gui/TaskView/TaskImageScale.ui diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index 6255b96070..b795387fa8 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -342,8 +342,8 @@ SET(Gui_UIC_SRCS Placement.ui TextureMapping.ui TaskView/TaskAppearance.ui - TaskView/TaskImageScale.ui TaskView/TaskOrientation.ui + TaskView/TaskImage.ui TaskView/TaskSelectLinkProperty.ui TaskElementColors.ui DlgObjectSelection.ui @@ -720,12 +720,12 @@ SET(Task_View_SRCS TaskView/TaskAppearance.cpp TaskView/TaskAppearance.h TaskView/TaskAppearance.ui - TaskView/TaskImageScale.cpp - TaskView/TaskImageScale.h - TaskView/TaskImageScale.ui TaskView/TaskOrientation.cpp TaskView/TaskOrientation.h TaskView/TaskOrientation.ui + TaskView/TaskImage.cpp + TaskView/TaskImage.h + TaskView/TaskImage.ui TaskView/TaskSelectLinkProperty.cpp TaskView/TaskSelectLinkProperty.h TaskView/TaskSelectLinkProperty.ui @@ -1235,8 +1235,8 @@ if(MSVC) propertyeditor/PropertyItemDelegate.cpp propertyeditor/PropertyModel.cpp TaskView/TaskAppearance.cpp - TaskView/TaskImageScale.cpp TaskView/TaskOrientation.cpp + TaskView/TaskImage.cpp TaskView/TaskSelectLinkProperty.cpp TaskView/TaskEditControl.cpp TaskView/TaskView.cpp diff --git a/src/Gui/TaskView/TaskImageScale.cpp b/src/Gui/TaskView/TaskImage.cpp similarity index 54% rename from src/Gui/TaskView/TaskImageScale.cpp rename to src/Gui/TaskView/TaskImage.cpp index a09e3c7573..c9d955b0b1 100644 --- a/src/Gui/TaskView/TaskImageScale.cpp +++ b/src/Gui/TaskView/TaskImage.cpp @@ -48,38 +48,31 @@ #include #include -#include "TaskImageScale.h" -#include "ui_TaskImageScale.h" +#include "TaskImage.h" +#include "ui_TaskImage.h" using namespace Gui; -/* TRANSLATOR Gui::TaskImageScale */ +/* TRANSLATOR Gui::TaskImage */ -TaskImageScale::TaskImageScale(Image::ImagePlane* obj, QWidget* parent) +TaskImage::TaskImage(Image::ImagePlane* obj, QWidget* parent) : QWidget(parent) - , ui(new Ui_TaskImageScale) + , ui(new Ui_TaskImage) , feature(obj) - , aspectRatio{1.0} + , aspectRatio(1.0) { ui->setupUi(this); ui->pushButtonCancel->hide(); - ui->spinBoxWidth->setValue(obj->getXSizeInPixel()); - ui->spinBoxHeight->setValue(obj->getYSizeInPixel()); + + initialiseTransparency(); aspectRatio = obj->XSize.getValue() / obj->YSize.getValue(); - connect(ui->spinBoxWidth, qOverload(&QSpinBox::valueChanged), - this, &TaskImageScale::changeWidth); - connect(ui->spinBoxHeight, qOverload(&QSpinBox::valueChanged), - this, &TaskImageScale::changeHeight); - connect(ui->pushButtonScale, &QPushButton::clicked, - this, &TaskImageScale::onInteractiveScale); - connect(ui->pushButtonCancel, &QPushButton::clicked, - this, &TaskImageScale::rejectScale); + connectSignals(); } -TaskImageScale::~TaskImageScale() +TaskImage::~TaskImage() { if (scale) { if (scale->isActive()) { @@ -89,33 +82,93 @@ TaskImageScale::~TaskImageScale() } } -void TaskImageScale::changeWidth() +void TaskImage::connectSignals() +{ + connect(ui->Reverse_checkBox, &QCheckBox::clicked, + this, &TaskImage::onPreview); + connect(ui->XY_radioButton, &QRadioButton::clicked, + this, &TaskImage::onPreview); + connect(ui->XZ_radioButton, &QRadioButton::clicked, + this, &TaskImage::onPreview); + connect(ui->YZ_radioButton, &QRadioButton::clicked, + this, &TaskImage::onPreview); + connect(ui->spinBoxZ, qOverload(&QuantitySpinBox::valueChanged), + this, &TaskImage::onPreview); + connect(ui->spinBoxX, qOverload(&QuantitySpinBox::valueChanged), + this, &TaskImage::onPreview); + connect(ui->spinBoxY, qOverload(&QuantitySpinBox::valueChanged), + this, &TaskImage::onPreview); + connect(ui->spinBoxRotation, qOverload(&QuantitySpinBox::valueChanged), + this, &TaskImage::onPreview); + connect(ui->spinBoxTransparency, qOverload(&QSpinBox::valueChanged), + this, &TaskImage::changeTransparency); + connect(ui->sliderTransparency, qOverload(&QSlider::valueChanged), + this, &TaskImage::changeTransparency); + + connect(ui->spinBoxWidth, qOverload(&QuantitySpinBox::valueChanged), + this, &TaskImage::changeWidth); + connect(ui->spinBoxHeight, qOverload(&QuantitySpinBox::valueChanged), + this, &TaskImage::changeHeight); + connect(ui->pushButtonScale, &QPushButton::clicked, + this, &TaskImage::onInteractiveScale); + connect(ui->pushButtonCancel, &QPushButton::clicked, + this, &TaskImage::rejectScale); +} + +void TaskImage::initialiseTransparency() +{ + auto vp = Application::Instance->getViewProvider(feature.get()); + App::Property* prop = vp->getPropertyByName("Transparency"); + if (prop && prop->getTypeId().isDerivedFrom(App::PropertyInteger::getClassTypeId())) { + auto Transparency = static_cast(prop); + ui->spinBoxTransparency->setValue(Transparency->getValue()); + ui->sliderTransparency->setValue(Transparency->getValue()); + } +} + +void TaskImage::changeTransparency(int val) +{ + if (feature.expired()) + return; + + auto vp = Application::Instance->getViewProvider(feature.get()); + App::Property* prop = vp->getPropertyByName("Transparency"); + if (prop && prop->getTypeId().isDerivedFrom(App::PropertyInteger::getClassTypeId())) { + auto Transparency = static_cast(prop); + Transparency->setValue(val); + + QSignalBlocker block(ui->spinBoxTransparency); + QSignalBlocker blocks(ui->sliderTransparency); + ui->spinBoxTransparency->setValue(val); + ui->sliderTransparency->setValue(val); + } +} + +void TaskImage::changeWidth(double val) { if (!feature.expired()) { - int value = ui->spinBoxWidth->value(); - feature->setXSizeInPixel(value); + feature->XSize.setValue(val); if (ui->checkBoxRatio->isChecked()) { QSignalBlocker block(ui->spinBoxWidth); - ui->spinBoxHeight->setValue(int(double(value) / aspectRatio)); + ui->spinBoxHeight->setValue(val / aspectRatio); } } } -void TaskImageScale::changeHeight() +void TaskImage::changeHeight(double val) { if (!feature.expired()) { - int value = ui->spinBoxHeight->value(); - feature->setYSizeInPixel(value); + feature->YSize.setValue(val); if (ui->checkBoxRatio->isChecked()) { QSignalBlocker block(ui->spinBoxHeight); - ui->spinBoxWidth->setValue(int(double(value) * aspectRatio)); + ui->spinBoxWidth->setValue(val * aspectRatio); } } } -View3DInventorViewer* TaskImageScale::getViewer() const +View3DInventorViewer* TaskImage::getViewer() const { if (!feature.expired()) { auto vp = Application::Instance->getViewProvider(feature.get()); @@ -129,7 +182,7 @@ View3DInventorViewer* TaskImageScale::getViewer() const return nullptr; } -void TaskImageScale::selectedPoints(size_t num) +void TaskImage::selectedPoints(size_t num) { if (num == 1) { ui->labelInstruction->setText(tr("Select second point")); @@ -139,23 +192,24 @@ void TaskImageScale::selectedPoints(size_t num) ui->pushButtonScale->setEnabled(true); ui->quantitySpinBox->setEnabled(true); ui->quantitySpinBox->setValue(scale->getDistance()); + ui->quantitySpinBox->setFocus(); } } -void TaskImageScale::scaleImage(double factor) +void TaskImage::scaleImage(double factor) { if (!feature.expired()) { feature->XSize.setValue(feature->XSize.getValue() * factor); feature->YSize.setValue(feature->YSize.getValue() * factor); QSignalBlocker blockW(ui->spinBoxWidth); - ui->spinBoxWidth->setValue(feature->getXSizeInPixel()); + ui->spinBoxWidth->setValue(feature->XSize.getValue()); QSignalBlocker blockH(ui->spinBoxHeight); - ui->spinBoxHeight->setValue(feature->getYSizeInPixel()); + ui->spinBoxHeight->setValue(feature->YSize.getValue()); } } -void TaskImageScale::startScale() +void TaskImage::startScale() { scale->activate(ui->checkBoxOutside->isChecked()); if (ui->checkBoxOutside->isChecked()) { @@ -171,13 +225,13 @@ void TaskImageScale::startScale() ui->quantitySpinBox->setEnabled(false); } -void TaskImageScale::acceptScale() +void TaskImage::acceptScale() { scaleImage(ui->quantitySpinBox->value().getValue() / scale->getDistance()); rejectScale(); } -void TaskImageScale::rejectScale() +void TaskImage::rejectScale() { scale->deactivate(); ui->labelInstruction->clear(); @@ -190,7 +244,7 @@ void TaskImageScale::rejectScale() scale->clearPoints(); } -void TaskImageScale::onInteractiveScale() +void TaskImage::onInteractiveScale() { if (!feature.expired() && !scale) { View3DInventorViewer* viewer = getViewer(); @@ -198,7 +252,7 @@ void TaskImageScale::onInteractiveScale() auto vp = Application::Instance->getViewProvider(feature.get()); scale = new InteractiveScale(viewer, vp); connect(scale, &InteractiveScale::selectedPoints, - this, &TaskImageScale::selectedPoints); + this, &TaskImage::selectedPoints); } } @@ -212,6 +266,143 @@ void TaskImageScale::onInteractiveScale() } } +void TaskImage::open() +{ + if (!feature.expired()) { + App::Document* doc = feature->getDocument(); + doc->openTransaction(QT_TRANSLATE_NOOP("Command", "Edit image")); + restore(feature->Placement.getValue()); + } +} + +void TaskImage::accept() +{ + if (!feature.expired()) { + App::Document* doc = feature->getDocument(); + doc->commitTransaction(); + doc->recompute(); + } +} + +void TaskImage::reject() +{ + if (!feature.expired()) { + App::Document* doc = feature->getDocument(); + doc->abortTransaction(); + feature->purgeTouched(); + } +} + +void TaskImage::onPreview() +{ + updateIcon(); + updatePlacement(); +} + +void TaskImage::restore(const Base::Placement& plm) +{ + if (feature.expired()) + return; + + QSignalBlocker blockW(ui->spinBoxWidth); + QSignalBlocker blockH(ui->spinBoxHeight); + ui->spinBoxWidth->setValue(feature->XSize.getValue()); + ui->spinBoxHeight->setValue(feature->YSize.getValue()); + + Base::Rotation rot = plm.getRotation(); + Base::Vector3d pos = plm.getPosition(); + + double yaw, pitch, roll; + rot.getYawPitchRoll(yaw, pitch, roll); + + double tol = 1.0e-5; + bool reverse = false; + if (fabs(pitch) < tol && (fabs(roll) < tol || fabs(roll - 180.) < tol)) { + if (fabs(roll - 180.) < tol) + reverse = true; + int inv = reverse ? -1 : 1; + ui->XY_radioButton->setChecked(true); + ui->spinBoxX->setValue(pos.x); + ui->spinBoxY->setValue(pos.y * inv); + ui->spinBoxZ->setValue(pos.z * inv); + ui->spinBoxRotation->setValue(yaw * inv); + } + else if (fabs(roll - 90.) < tol && (fabs(yaw) < tol || fabs(yaw - 180.) < tol)) { + if (fabs(yaw - 180.) < tol) + reverse = true; + int inv = reverse ? -1 : 1; + ui->XZ_radioButton->setChecked(true); + ui->spinBoxX->setValue(- inv * pos.x); + ui->spinBoxY->setValue(pos.z); + ui->spinBoxZ->setValue(inv * pos.y); + ui->spinBoxRotation->setValue(- pitch); + } + else if (fabs(roll - 90.) < tol && (fabs(yaw - 90.) < tol || fabs(yaw + 90.) < tol)) { + if (fabs(yaw + 90.) < tol) + reverse = true; + int inv = reverse ? -1 : 1; + ui->YZ_radioButton->setChecked(true); + ui->spinBoxX->setValue(-inv * pos.y); + ui->spinBoxY->setValue(pos.z); + ui->spinBoxZ->setValue(inv * pos.x); + ui->spinBoxRotation->setValue(-pitch); + } + + ui->Reverse_checkBox->setChecked(reverse); + + onPreview(); +} + +void TaskImage::updatePlacement() +{ + Base::Placement Pos; + double offsetX = ui->spinBoxX->value().getValue(); + double offsetY = ui->spinBoxY->value().getValue(); + double offsetZ = ui->spinBoxZ->value().getValue(); + double angle = ui->spinBoxRotation->value().getValue(); + bool reverse = ui->Reverse_checkBox->isChecked(); + + Base::Rotation rot; + double dir = reverse ? 180. : 0.; + int inv = reverse ? -1 : 1; + + if (ui->XY_radioButton->isChecked()) { + rot.setYawPitchRoll(inv * angle, 0., dir); + Pos = Base::Placement(Base::Vector3d(offsetX, inv * offsetY, inv * offsetZ), rot); + } + else if (ui->XZ_radioButton->isChecked()) { + rot.setYawPitchRoll(dir, -angle, 90.); + Pos = Base::Placement(Base::Vector3d(- inv * offsetX, inv * offsetZ, offsetY), rot); + } + else if (ui->YZ_radioButton->isChecked()) { + rot.setYawPitchRoll(90. - dir, -angle, 90.); + Pos = Base::Placement(Base::Vector3d(inv * offsetZ, - inv * offsetX, offsetY), rot); + } + + if (!feature.expired()) { + feature->Placement.setValue(Pos); + } +} + +void TaskImage::updateIcon() +{ + std::string icon; + bool reverse = ui->Reverse_checkBox->isChecked(); + if (ui->XY_radioButton->isChecked()) { + icon = reverse ? "view-bottom" : "view-top"; + } + else if (ui->XZ_radioButton->isChecked()) { + icon = reverse ? "view-rear" : "view-front"; + } + else if (ui->YZ_radioButton->isChecked()) { + icon = reverse ? "view-left" : "view-right"; + } + + ui->previewLabel->setPixmap( + Gui::BitmapFactory().pixmapFromSvg(icon.c_str(), + ui->previewLabel->size())); +} + // ---------------------------------------------------------------------------- InteractiveScale::InteractiveScale(View3DInventorViewer* view, ViewProvider* vp) @@ -366,4 +557,32 @@ void InteractiveScale::getMousePosition(void * ud, SoEventCallback * ecb) } } -#include "moc_TaskImageScale.cpp" +// ---------------------------------------------------------------------------- + +TaskImageDialog::TaskImageDialog(Image::ImagePlane* obj) +{ + widget = new TaskImage(obj); + Gui::TaskView::TaskBox* taskbox = new Gui::TaskView::TaskBox( + QPixmap(), widget->windowTitle(), true, nullptr); + taskbox->groupLayout()->addWidget(widget); + Content.push_back(taskbox); +} + +void TaskImageDialog::open() +{ + widget->open(); +} + +bool TaskImageDialog::accept() +{ + widget->accept(); + return true; +} + +bool TaskImageDialog::reject() +{ + widget->reject(); + return true; +} + +#include "moc_TaskImage.cpp" diff --git a/src/Gui/TaskView/TaskImageScale.h b/src/Gui/TaskView/TaskImage.h similarity index 75% rename from src/Gui/TaskView/TaskImageScale.h rename to src/Gui/TaskView/TaskImage.h index 4327abee4c..43bc490171 100644 --- a/src/Gui/TaskView/TaskImageScale.h +++ b/src/Gui/TaskView/TaskImage.h @@ -21,8 +21,8 @@ * * **************************************************************************/ -#ifndef GUI_TASKIMAGESCALE_H -#define GUI_TASKIMAGESCALE_H +#ifndef GUI_TASKIMAGE_H +#define GUI_TASKIMAGE_H #include #include @@ -78,18 +78,23 @@ private: std::vector points; }; -class Ui_TaskImageScale; -class TaskImageScale : public QWidget +class Ui_TaskImage; +class TaskImage : public QWidget { Q_OBJECT public: - explicit TaskImageScale(Image::ImagePlane* obj, QWidget* parent = nullptr); - ~TaskImageScale() override; + explicit TaskImage(Image::ImagePlane* obj, QWidget* parent = nullptr); + ~TaskImage() override; + + void open(); + void accept(); + void reject(); private: - void changeWidth(); - void changeHeight(); + void initialiseTransparency(); + void connectSignals(); + void onInteractiveScale(); View3DInventorViewer* getViewer() const; void selectedPoints(size_t num); @@ -98,13 +103,43 @@ private: void acceptScale(); void rejectScale(); + void restore(const Base::Placement&); + void onPreview(); + void updateIcon(); + void updatePlacement(); + +private Q_SLOTS: + void changeTransparency(int val); + void changeWidth(double val); + void changeHeight(double val); + private: - std::unique_ptr ui; + std::unique_ptr ui; QPointer scale; App::WeakPtrT feature; double aspectRatio; }; +class TaskImageDialog : public Gui::TaskView::TaskDialog +{ + Q_OBJECT + +public: + explicit TaskImageDialog(Image::ImagePlane* obj); + +public: + void open() override; + bool accept() override; + bool reject() override; + + QDialogButtonBox::StandardButtons getStandardButtons() const override { + return QDialogButtonBox::Ok | QDialogButtonBox::Cancel; + } + +private: + TaskImage* widget; +}; + } -#endif // GUI_TASKIMAGESCALE_H +#endif // GUI_TASKIMAGE_H diff --git a/src/Gui/TaskView/TaskImage.ui b/src/Gui/TaskView/TaskImage.ui new file mode 100644 index 0000000000..7efbd2c21d --- /dev/null +++ b/src/Gui/TaskView/TaskImage.ui @@ -0,0 +1,346 @@ + + + Gui::TaskImage + + + + 0 + 0 + 421 + 267 + + + + Image plane settings + + + + + + + + Planes + + + + + + XY-Plane + + + true + + + + + + + XZ-Plane + + + + + + + YZ-Plane + + + + + + + + + + + 48 + 48 + + + + + 48 + 48 + + + + Preview + + + + + + + + + Reverse direction + + + + + + + Offset: + + + + + + + mm + + + -999999999.000000000000000 + + + 999999999.000000000000000 + + + + + + + X distance: + + + + + + + mm + + + -999999999.000000000000000 + + + 999999999.000000000000000 + + + + + + + Y distance: + + + + + + + mm + + + -999999999.000000000000000 + + + 999999999.000000000000000 + + + + + + + Rotation : + + + + + + + deg + + + + + + + + + Transparency : + + + + + + + 100 + + + Qt::Horizontal + + + + + + + 0 + + + 0 + + + 100 + + + + + + + + + Image size + + + + + + + + Width: + + + + + + + mm + + + 0.00000001 + + + 999999999.000000000000000 + + + + + + + Height: + + + + + + + mm + + + 0.00000001 + + + 999999999.000000000000000 + + + + + + + + + Keep aspect ratio + + + true + + + + + + + + + + + + + + + + + + Interactively scale the image + + + Interactive + + + + + + + Cancel + + + + + + + Qt::Horizontal + + + + 136 + 20 + + + + + + + + + 0 + 0 + + + + Allow points outside the image + + + + + + + + + + + Desired distance: + + + + + + + false + + + mm + + + + + + + + + + + + + + + + + + + + Gui::QuantitySpinBox + QWidget +
Gui/QuantitySpinBox.h
+
+
+ + +
diff --git a/src/Gui/TaskView/TaskImageScale.ui b/src/Gui/TaskView/TaskImageScale.ui deleted file mode 100644 index bc51452a36..0000000000 --- a/src/Gui/TaskView/TaskImageScale.ui +++ /dev/null @@ -1,184 +0,0 @@ - - - Gui::TaskImageScale - - - - 0 - 0 - 421 - 267 - - - - Scale image - - - - - - Image size - - - - - - - - Width: - - - - - - - px - - - 1 - - - 100000000 - - - - - - - Height: - - - - - - - px - - - 1 - - - 100000000 - - - - - - - - - Keep aspect ratio - - - true - - - - - - - - - - - - - - - - - - Interactively scale the image - - - Interactive - - - - - - - Cancel - - - - - - - Qt::Horizontal - - - - 136 - 20 - - - - - - - - - 0 - 0 - - - - Allow points outside the image - - - - - - - - - - - Desired distance: - - - - - - - false - - - mm - - - - - - - - - - - - - - - - - - - - Gui::QuantitySpinBox - QWidget -
Gui/QuantitySpinBox.h
-
-
- - spinBoxWidth - spinBoxHeight - checkBoxRatio - pushButtonScale - pushButtonCancel - checkBoxOutside - quantitySpinBox - - - -
diff --git a/src/Gui/ViewProviderImagePlane.cpp b/src/Gui/ViewProviderImagePlane.cpp index 267c9fc99d..0f16a3afc2 100644 --- a/src/Gui/ViewProviderImagePlane.cpp +++ b/src/Gui/ViewProviderImagePlane.cpp @@ -41,8 +41,7 @@ #include #include #include -#include -#include +#include #include #include "ViewProviderImagePlane.h" @@ -159,12 +158,9 @@ bool ViewProviderImagePlane::doubleClicked() void ViewProviderImagePlane::manipulateImage() { - auto dialog = new TaskOrientationDialog( - dynamic_cast(getObject()) - ); - dialog->addTaskBox(new TaskImageScale( + auto dialog = new TaskImageDialog( dynamic_cast(getObject()) - )); + ); Gui::Control().showDialog(dialog); }