Files
create/src/Mod/TechDraw/Gui/TaskProjGroup.cpp
Markus Reitböck 63ab3de853 TechDraw: use CMake to generate precompiled headers on all platforms
"Professional CMake" book suggest the following:

"Targets should build successfully with or without compiler support for precompiled headers. It
 should be considered an optimization, not a requirement. In particular, do not explicitly include a
 precompile header (e.g. stdafx.h) in the source code, let CMake force-include an automatically
 generated precompile header on the compiler command line instead. This is more portable across
 the major compilers and is likely to be easier to maintain. It will also avoid warnings being
 generated from certain code checking tools like iwyu (include what you use)."

Therefore, removed the "#include <PreCompiled.h>" from sources, also
there is no need for the "#ifdef _PreComp_" anymore
2025-09-23 00:50:59 +02:00

1025 lines
35 KiB
C++

/***************************************************************************
* Copyright (c) 2014 Joe Dowsett <dowsettjoe[at]yahoo[dot]co[dot]uk> *
* Copyright (c) 2014 Luke Parry <l.parry@warwick.ac.uk> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
# include <QMessageBox>
# include <QGroupBox>
# include <QLabel>
# include <QScreen>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <QDialog>
#include <App/Document.h>
#include <Base/Console.h>
#include <Base/Tools.h>
#include <Gui/Application.h>
#include <Gui/BitmapFactory.h>
#include <Gui/Command.h>
#include <Gui/Document.h>
#include <Gui/WaitCursor.h>
#include <Gui/QuantitySpinBox.h>
#include <Mod/TechDraw/App/DrawPage.h>
#include <Mod/TechDraw/App/DrawView.h>
#include <Mod/TechDraw/App/DrawViewPart.h>
#include <Mod/TechDraw/App/DrawProjGroup.h>
#include <Mod/TechDraw/App/DrawProjGroupItem.h>
#include <Mod/TechDraw/App/DrawUtil.h>
#include <Mod/TechDraw/App/Preferences.h>
#include "DrawGuiUtil.h"
#include "TaskProjGroup.h"
#include "ui_TaskProjGroup.h"
#include "MDIViewPage.h"
#include "ViewProviderPage.h"
#include "ViewProviderDrawingView.h"
#include "ViewProviderProjGroupItem.h"
#include "ViewProviderProjGroup.h"
using namespace Gui;
using namespace TechDraw;
using namespace TechDrawGui;
TaskProjGroup::TaskProjGroup(TechDraw::DrawView* featView, bool mode) :
ui(new Ui_TaskProjGroup),
view(featView),
multiView(dynamic_cast<TechDraw::DrawProjGroup*>(view)),
m_createMode(mode),
blockCheckboxes(false)
{
ui->setupUi(this);
m_page = view->findParentPage();
m_viewName = view->getNameInDocument();
Gui::Document* activeGui = Gui::Application::Instance->getDocument(m_page->getDocument());
Gui::ViewProvider* vp = activeGui->getViewProvider(m_page);
auto* dvp = static_cast<ViewProviderPage*>(vp);
m_mdi = dvp->getMDIViewPage();
connectWidgets();
initializeUi();
setUiPrimary();
updateUi();
saveGroupState();
blockUpdate = false;
}
void TaskProjGroup::connectWidgets()
{
// Rotation buttons
connect(ui->butTopRotate, &QPushButton::clicked, this, &TaskProjGroup::rotateButtonClicked);
connect(ui->butCWRotate, &QPushButton::clicked, this, &TaskProjGroup::rotateButtonClicked);
connect(ui->butRightRotate, &QPushButton::clicked, this, &TaskProjGroup::rotateButtonClicked);
connect(ui->butDownRotate, &QPushButton::clicked, this, &TaskProjGroup::rotateButtonClicked);
connect(ui->butLeftRotate, &QPushButton::clicked, this, &TaskProjGroup::rotateButtonClicked);
connect(ui->butCCWRotate, &QPushButton::clicked, this, &TaskProjGroup::rotateButtonClicked);
connect(ui->butFront, &QPushButton::clicked, this, &TaskProjGroup::rotateButtonClicked);
connect(ui->butCam, &QPushButton::clicked, this, &TaskProjGroup::rotateButtonClicked);
connect(ui->lePrimary, &QPushButton::clicked, this, &TaskProjGroup::customDirectionClicked);
// Slot for Scale Type
connect(ui->cmbScaleType, qOverload<int>(&QComboBox::currentIndexChanged), this, &TaskProjGroup::scaleTypeChanged);
connect(ui->sbScaleNum, qOverload<int>(&QSpinBox::valueChanged), this, &TaskProjGroup::scaleManuallyChanged);
connect(ui->sbScaleDen, qOverload<int>(&QSpinBox::valueChanged), this, &TaskProjGroup::scaleManuallyChanged);
// Slot for Projection Type (layout)
connect(ui->projection, qOverload<int>(&QComboBox::currentIndexChanged), this, [this](int index) {
projectionTypeChanged(ui->projection->itemText(index));
});
// Spacing
connect(ui->cbAutoDistribute, &QPushButton::clicked, this, &TaskProjGroup::AutoDistributeClicked);
connect(ui->sbXSpacing, qOverload<double>(&QuantitySpinBox::valueChanged), this, &TaskProjGroup::spacingChanged);
connect(ui->sbYSpacing, qOverload<double>(&QuantitySpinBox::valueChanged), this, &TaskProjGroup::spacingChanged);
}
void TaskProjGroup::initializeUi()
{
if (!view) {
return;
}
if (multiView) {
// we have a projection group as input
ui->projection->setCurrentIndex(multiView->ProjectionType.getValue());
ui->cbAutoDistribute->setChecked(multiView->AutoDistribute.getValue());
// disable if no AutoDistribute
ui->sbXSpacing->setEnabled(multiView->AutoDistribute.getValue());
ui->sbYSpacing->setEnabled(multiView->AutoDistribute.getValue());
ui->sbXSpacing->setValue(multiView->spacingX.getValue());
ui->sbYSpacing->setValue(multiView->spacingY.getValue());
} else {
ui->projection->setCurrentIndex(Preferences::projectionAngle());
ui->cbAutoDistribute->setChecked(Preferences::groupAutoDistribute());
ui->sbXSpacing->setValue(Preferences::groupSpaceX());
ui->sbYSpacing->setValue(Preferences::groupSpaceY());
}
setFractionalScale(view->getScale());
ui->cmbScaleType->setCurrentIndex(view->ScaleType.getValue());
//Allow or prevent scale changing initially
if (view->ScaleType.isValue("Custom")) {
ui->sbScaleNum->setEnabled(true);
ui->sbScaleDen->setEnabled(true);
}
else {
ui->sbScaleNum->setEnabled(false);
ui->sbScaleDen->setEnabled(false);
}
// Initially toggle view checkboxes if needed
setupViewCheckboxes(true);
ui->sbXSpacing->setUnit(Base::Unit::Length);
ui->sbYSpacing->setUnit(Base::Unit::Length);
if (Preferences::useCameraDirection()) {
ui->butCam->setChecked(true);
} else {
ui->butFront->setChecked(true);
}
}
//! enable/disable the appropriate widgets
void TaskProjGroup::updateUi()
{
if (multiView) {
setWindowTitle(QObject::tr("Projection Group"));
ui->projection->show();
ui->cbAutoDistribute->show();
ui->sbXSpacing->show();
ui->sbYSpacing->show();
ui->label_7->show();
ui->label_10->show();
ui->label_11->show();
}
else {
setWindowTitle(QObject::tr("New View"));
ui->projection->hide();
ui->cbAutoDistribute->hide();
ui->sbXSpacing->hide();
ui->sbYSpacing->hide();
ui->label_7->hide();
ui->label_10->hide();
ui->label_11->hide();
// if the view is not a proj group item, then we disable secondary projs.
auto* dpgi = dynamic_cast<TechDraw::DrawProjGroupItem*>(view);
if (!dpgi) {
ui->secondaryProjGroupbox->hide();
}
}
}
void TaskProjGroup::saveGroupState()
{
if (!view) {
return;
}
m_saveScaleType = view->ScaleType.getValueAsString();
m_saveScale = view->Scale.getValue();
if (multiView) {
m_saveSource = multiView->Source.getValues();
m_saveProjType = multiView->ProjectionType.getValueAsString();
m_saveAutoDistribute = multiView->AutoDistribute.getValue();
m_saveSpacingX = multiView->spacingX.getValue();
m_saveSpacingY = multiView->spacingY.getValue();
DrawProjGroupItem* anchor = multiView->getAnchor();
m_saveDirection = anchor->Direction.getValue();
for( const auto it : multiView->Views.getValues() ) {
auto view( dynamic_cast<DrawProjGroupItem *>(it) );
if (view) {
m_saveViewNames.emplace_back(view->Type.getValueAsString());
}
}
}
}
//never used?
void TaskProjGroup::restoreGroupState()
{
if (!view) {
return;
}
view->ScaleType.setValue(m_saveScaleType.c_str());
view->Scale.setValue(m_saveScale);
if (multiView) {
multiView->ProjectionType.setValue(m_saveProjType.c_str());
multiView->AutoDistribute.setValue(m_saveAutoDistribute);
multiView->spacingX.setValue(m_saveSpacingX);
multiView->spacingY.setValue(m_saveSpacingY);
multiView->purgeProjections();
for(auto & sv : m_saveViewNames) {
if (sv != "Front") {
multiView->addProjection(sv.c_str());
}
}
}
}
void TaskProjGroup::viewToggled(bool toggle)
{
Gui::WaitCursor wc;
bool changed = false;
// Obtain name of checkbox
int index = sender()->objectName().mid(7).toInt();
const char *viewNameCStr = viewChkIndexToCStr(index);
if (!blockCheckboxes) {
if (multiView) {
// Check if only front is left. If so switch to normal view.
if (multiView->Views.getValues().size() == 2 && !toggle) {
turnProjGroupToView();
wc.restoreCursor();
return;
}
}
else {
// If toggle then we remove the view object and create a proj group instead.
turnViewToProjGroup();
changed = true;
}
}
if (toggle && !multiView->hasProjection(viewNameCStr)) {
Gui::Command::doCommand(Gui::Command::Doc,
"App.activeDocument().%s.addProjection('%s')",
multiView->getNameInDocument(), viewNameCStr);
changed = true;
}
else if (!toggle && multiView->hasProjection(viewNameCStr)) {
if (multiView->canDelete(viewNameCStr)) {
multiView->removeProjection( viewNameCStr );
changed = true;
}
}
if (changed) {
// necessary to prevent position problems
Gui::Document* activeGui = Gui::Application::Instance->getDocument(m_page->getDocument());
auto* vppg = static_cast<ViewProviderProjGroup*>(activeGui->getViewProvider(multiView));
vppg->regroupSubViews();
if (view->ScaleType.isValue("Automatic")) {
double scale = view->getScale();
setFractionalScale(scale);
}
view->recomputeFeature();
}
wc.restoreCursor();
}
void TaskProjGroup::turnViewToProjGroup()
{
App::Document* doc = view->getDocument();
std::string multiViewName = doc->getUniqueObjectName("ProjGroup");
Gui::Command::doCommand(Gui::Command::Gui, "App.activeDocument().addObject('TechDraw::DrawProjGroup', '%s')", multiViewName.c_str());
Gui::Command::doCommand(Gui::Command::Gui, "App.activeDocument().%s.addView(App.activeDocument().%s)", view->findParentPage()->getNameInDocument(), multiViewName.c_str());
auto* viewPart = static_cast<TechDraw::DrawViewPart*>(view);
multiView = static_cast<TechDraw::DrawProjGroup*>(doc->getObject(multiViewName.c_str()));
multiView->Source.setValues(viewPart->Source.getValues());
multiView->XSource.setValues(viewPart->XSource.getValues());
multiView->X.setValue(viewPart->X.getValue());
multiView->Y.setValue(viewPart->Y.getValue());
multiView->Scale.setValue(viewPart->Scale.getValue());
multiView->ScaleType.setValue(viewPart->ScaleType.getValue());
multiView->ProjectionType.setValue(Preferences::projectionAngle());
multiView->addView(viewPart);
multiView->Anchor.setValue(viewPart);
multiView->Anchor.purgeTouched();
viewPart->X.setValue(0.0);
viewPart->Y.setValue(0.0);
viewPart->ScaleType.setValue("Custom");
viewPart->ScaleType.setStatus(App::Property::Hidden, true);
viewPart->Scale.setStatus(App::Property::Hidden, true);
viewPart->Label.setValue("Front");
viewPart->LockPosition.setValue(true);
viewPart->LockPosition.setStatus(App::Property::ReadOnly, true); //Front should stay locked.
viewPart->LockPosition.purgeTouched();
m_page->requestPaint();
view = multiView;
m_page->removeView(viewPart); // prevent multiple entries in tree
updateUi();
}
void TaskProjGroup::turnProjGroupToView()
{
TechDraw::DrawViewPart* viewPart = multiView->getAnchor();
viewPart->Scale.setValue(multiView->Scale.getValue());
viewPart->ScaleType.setValue(multiView->ScaleType.getValue());
viewPart->Scale.setStatus(App::Property::Hidden, false);
viewPart->ScaleType.setStatus(App::Property::Hidden, false);
viewPart->Label.setValue("View");
viewPart->LockPosition.setValue(false);
viewPart->LockPosition.setStatus(App::Property::ReadOnly, false);
viewPart->X.setValue(multiView->X.getValue());
viewPart->Y.setValue(multiView->Y.getValue());
m_page->addView(viewPart);
// remove viewPart from views before deleting the group.
multiView->removeView(viewPart);
Gui::Command::doCommand(Gui::Command::Gui, "App.activeDocument().removeObject('%s')", multiView->getNameInDocument());
viewPart->recomputeFeature();
Gui::Document* activeGui = Gui::Application::Instance->getDocument(m_page->getDocument());
auto* vpView = static_cast<ViewProviderProjGroupItem*>(activeGui->getViewProvider(viewPart));
if (vpView) {
vpView->updateIcon();
vpView->fixSceneDependencies();
}
view = viewPart;
multiView = nullptr;
updateUi();
}
void TaskProjGroup::customDirectionClicked()
{
auto* dirEditDlg = new DirectionEditDialog();
if (multiView) {
dirEditDlg->setDirection(multiView->getAnchor()->Direction.getValue());
dirEditDlg->setAngle(0.0);
}
else {
auto* viewPart = static_cast<TechDraw::DrawViewPart*>(view);
dirEditDlg->setDirection(viewPart->Direction.getValue());
dirEditDlg->setAngle(0.0);
}
if (dirEditDlg->exec() == QDialog::Accepted) {
if (multiView) {
multiView->getAnchor()->Direction.setValue(dirEditDlg->getDirection());
multiView->spin(Base::toRadians(dirEditDlg->getAngle()));
}
else {
auto* viewPart = static_cast<TechDraw::DrawViewPart*>(view);
viewPart->Direction.setValue(dirEditDlg->getDirection());
viewPart->spin(Base::toRadians(dirEditDlg->getAngle()));
}
setUiPrimary();
}
delete dirEditDlg;
}
void TaskProjGroup::rotateButtonClicked()
{
if ( view && ui ) {
const QObject *clicked = sender();
auto handleCameraButton = [&]() {
std::string faceName;
App::DocumentObject* obj = nullptr;
auto selection = Gui::Command::getSelection().getSelectionEx();
for (auto& sel : selection) {
for (auto& sub : sel.getSubNames()) {
if (TechDraw::DrawUtil::getGeomTypeFromName(sub) == "Face") {
obj = sel.getObject();
faceName = sub;
break;
}
}
if (!faceName.empty()) {
break;
}
}
std::pair<Base::Vector3d, Base::Vector3d> dirs = !faceName.empty() ?
DrawGuiUtil::getProjDirFromFace(obj, faceName)
: DrawGuiUtil::get3DDirAndRot();
return dirs;
};
if (multiView) {
//change Front View Dir by 90
if (clicked == ui->butTopRotate) multiView->rotate(RotationMotion::Up);
else if (clicked == ui->butDownRotate) multiView->rotate(RotationMotion::Down);
else if (clicked == ui->butRightRotate) multiView->rotate(RotationMotion::Right);
else if (clicked == ui->butLeftRotate) multiView->rotate(RotationMotion::Left);
else if (clicked == ui->butCWRotate) multiView->spin(SpinDirection::CW);
else if (clicked == ui->butCCWRotate) multiView->spin(SpinDirection::CCW);
else if (clicked == ui->butFront) {
multiView->getAnchor()->Direction.setValue(Base::Vector3d(0.0, -1.0, 0.0));
multiView->getAnchor()->RotationVector.setValue(Base::Vector3d(1.0, 0.0, 0.0));
multiView->getAnchor()->XDirection.setValue(Base::Vector3d(1.0, 0.0, 0.0));
multiView->updateSecondaryDirs();
}
else if (clicked == ui->butCam) {
std::pair<Base::Vector3d, Base::Vector3d> dirs = handleCameraButton();
multiView->getAnchor()->Direction.setValue(dirs.first);
multiView->getAnchor()->RotationVector.setValue(dirs.second);
multiView->getAnchor()->XDirection.setValue(dirs.second);
multiView->updateSecondaryDirs();
}
}
else {
auto* viewPart = static_cast<TechDraw::DrawViewPart*>(view);
if (clicked == ui->butTopRotate) viewPart->rotate(RotationMotion::Up);
else if (clicked == ui->butDownRotate) viewPart->rotate(RotationMotion::Down);
else if (clicked == ui->butRightRotate) viewPart->rotate(RotationMotion::Right);
else if (clicked == ui->butLeftRotate) viewPart->rotate(RotationMotion::Left);
else if (clicked == ui->butCWRotate) viewPart->spin(SpinDirection::CW);
else if (clicked == ui->butCCWRotate) viewPart->spin(SpinDirection::CCW);
else if (clicked == ui->butFront) {
viewPart->Direction.setValue(Base::Vector3d(0.0,-1.0,0.0));
viewPart->XDirection.setValue(Base::Vector3d(1.0, 0.0, 0.0));
viewPart->recomputeFeature();
}
else if (clicked == ui->butCam) {
std::pair<Base::Vector3d, Base::Vector3d> dirs = handleCameraButton();
viewPart->Direction.setValue(dirs.first);
viewPart->XDirection.setValue(dirs.second);
viewPart->recomputeFeature();
}
}
setUiPrimary();
}
}
//void TaskProjGroup::projectionTypeChanged(int index)
void TaskProjGroup::projectionTypeChanged(QString qText)
{
if(blockUpdate || !multiView) {
return;
}
if (qText == QStringLiteral("Page")) {
multiView->ProjectionType.setValue("Default");
}
else {
std::string text = qText.toStdString();
multiView->ProjectionType.setValue(text.c_str());
}
// Update checkboxes so checked state matches the drawing
blockCheckboxes = true;
setupViewCheckboxes();
blockCheckboxes = false;
// set the tooltips of the checkboxes
ui->chkView0->setToolTip(getToolTipForBox(0));
ui->chkView1->setToolTip(getToolTipForBox(1));
ui->chkView2->setToolTip(getToolTipForBox(2));
ui->chkView3->setToolTip(getToolTipForBox(3));
ui->chkView4->setToolTip(getToolTipForBox(4));
ui->chkView5->setToolTip(getToolTipForBox(5));
ui->chkView6->setToolTip(getToolTipForBox(6));
ui->chkView7->setToolTip(getToolTipForBox(7));
ui->chkView8->setToolTip(getToolTipForBox(8));
ui->chkView9->setToolTip(getToolTipForBox(9));
// R/L and T/B view need to be repositioned and just recomputing a single view will not do this
multiView->recomputeChildren();
}
void TaskProjGroup::scaleTypeChanged(int index)
{
if (blockUpdate) {
return;
}
//defaults to prevent scale changing
ui->sbScaleNum->setEnabled(false);
ui->sbScaleDen->setEnabled(false);
if (index == 0) {
// Document Scale Type
view->ScaleType.setValue("Page");
}
else if (index == 1) {
// Automatic Scale Type
//block recompute
view->ScaleType.setValue("Automatic");
double autoScale = view->autoScale();
view->Scale.setValue(autoScale);
//unblock recompute
}
else if (index == 2) {
// Custom Scale Type
//block recompute
view->ScaleType.setValue("Custom");
ui->sbScaleNum->setEnabled(true);
ui->sbScaleDen->setEnabled(true);
int numerator = ui->sbScaleNum->value();
int denominator = ui->sbScaleDen->value();
double scale = (double) numerator / (double) denominator;
view->Scale.setValue(scale);
//unblock recompute
}
}
void TaskProjGroup::AutoDistributeClicked(bool clicked)
{
if (blockUpdate || !multiView) {
return;
}
multiView->AutoDistribute.setValue(clicked);
multiView->recomputeFeature();
}
void TaskProjGroup::spacingChanged()
{
if (blockUpdate || !multiView) {
return;
}
multiView->spacingX.setValue(ui->sbXSpacing->value().getValue());
multiView->spacingY.setValue(ui->sbYSpacing->value().getValue());
multiView->autoPositionChildren();
}
void TaskProjGroup::updateTask()
{
// Update the scale type
blockUpdate = true;
ui->cmbScaleType->setCurrentIndex(view->ScaleType.getValue());
// Update the scale value
setFractionalScale(view->getScale());
blockUpdate = false;
}
void TaskProjGroup::setFractionalScale(double newScale)
{
blockUpdate = true;
std::pair<int, int> fraction = DrawUtil::nearestFraction(newScale);
ui->sbScaleNum->setValue(fraction.first);
ui->sbScaleDen->setValue(fraction.second);
blockUpdate = false;
}
void TaskProjGroup::scaleManuallyChanged(int unused)
{
Q_UNUSED(unused);
if(blockUpdate) {
return;
}
if (!view->ScaleType.isValue("Custom")) { //ignore if not custom!
return;
}
int numerator = ui->sbScaleNum->value();
int denominator = ui->sbScaleDen->value();
double scale = (double) numerator / (double) denominator;
Gui::Command::doCommand(Gui::Command::Doc, "App.activeDocument().%s.Scale = %f", view->getNameInDocument()
, scale);
view->recomputeFeature();
}
void TaskProjGroup::changeEvent(QEvent *event)
{
if (event->type() == QEvent::LanguageChange) {
ui->retranslateUi(this);
}
}
const char * TaskProjGroup::viewChkIndexToCStr(int index)
{
// Third Angle: FTL T FTRight
// L F Right Rear
// FBL B FBRight
//
// First Angle: FBRight B FBL
// Right F L Rear
// FTRight T FTL
bool thirdAngle = useThirdAngle();
switch(index) {
case 0: return (thirdAngle ? "FrontTopLeft" : "FrontBottomRight");
case 1: return (thirdAngle ? "Top" : "Bottom");
case 2: return (thirdAngle ? "FrontTopRight" : "FrontBottomLeft");
case 3: return (thirdAngle ? "Left" : "Right");
case 4: return "Front";
case 5: return (thirdAngle ? "Right" : "Left");
case 6: return "Rear";
case 7: return (thirdAngle ? "FrontBottomLeft" : "FrontTopRight");
case 8: return (thirdAngle ? "Bottom" : "Top");
case 9: return (thirdAngle ? "FrontBottomRight" : "FrontTopLeft");
default: return nullptr;
}
}
QString TaskProjGroup::getToolTipForBox(int boxNumber)
{
bool thirdAngle = useThirdAngle();
switch(boxNumber) {
case 0: {return (thirdAngle ? tr("FrontTopLeft") : tr("FrontBottomRight")); break;}
case 1: {return (thirdAngle ? tr("Top") : tr("Bottom")); break;}
case 2: {return (thirdAngle ? tr("FrontTopRight") : tr("FrontBottomLeft")); break;}
case 3: {return (thirdAngle ? tr("Left" ): tr("Right")); break;}
case 4: {return tr("Front"); break; }
case 5: {return (thirdAngle ? tr("Right") : tr("Left")); break;}
case 6: {return tr("Rear"); break; }
case 7: {return (thirdAngle ? tr("FrontBottomLeft") : tr("FrontTopRight")); break;}
case 8: {return (thirdAngle ? tr("Bottom") : tr("Top")); break;}
case 9: {return (thirdAngle ? tr("FrontBottomRight") : tr("FrontTopLeft")); break;}
default: {return {}; break;}
}
}
bool TaskProjGroup::useThirdAngle()
{
if (!view) {
// something is wrong if this happens
throw Base::RuntimeError("TaskProjGroup - no view!");
}
auto page = view->findParentPage();
if (!page) {
return false;
}
bool thirdAngle = (bool) Preferences::projectionAngle();
if (!multiView) {
return thirdAngle;
}
if (multiView->usedProjectionType().isValue("Third Angle")) {
thirdAngle = true;
} else if (multiView->usedProjectionType().isValue("Default") &&
page->ProjectionType.isValue("Third Angle")) {
thirdAngle = true;
}
return thirdAngle;
}
void TaskProjGroup::setupViewCheckboxes(bool addConnections)
{
if (!view) {
return;
}
// There must be a better way to construct this list...
QCheckBox * viewCheckboxes[] = { ui->chkView0,
ui->chkView1,
ui->chkView2,
ui->chkView3,
ui->chkView4,
ui->chkView5,
ui->chkView6,
ui->chkView7,
ui->chkView8,
ui->chkView9 };
for (int i = 0; i < 10; ++i) {
QCheckBox *box = viewCheckboxes[i];
box->setToolTip(getToolTipForBox(i));
const char *viewStr = viewChkIndexToCStr(i);
if (!multiView) {
box->setCheckState(strcmp(viewStr, "Front") == 0 ? Qt::Checked : Qt::Unchecked);
}
if (addConnections) {
connect(box, &QCheckBox::toggled, this, &TaskProjGroup::viewToggled);
}
if (multiView) {
if (viewStr && multiView->hasProjection(viewStr)) {
box->setCheckState(Qt::Checked);
if (!multiView->canDelete(viewStr)) {
box->setEnabled(false);
}
}
else {
box->setCheckState(Qt::Unchecked);
}
}
}
}
//! sets the main direction of the view
// Note: does not set any of the other values that one would expect to be initialized
void TaskProjGroup::setUiPrimary()
{
Base::Vector3d frontDir;
if (multiView) {
frontDir = multiView->getAnchorDirection();
}
else {
auto* viewPart = static_cast<TechDraw::DrawViewPart*>(view);
if (viewPart) {
frontDir = viewPart->Direction.getValue();
}
}
ui->lePrimary->setText(formatVector(frontDir));
}
QString TaskProjGroup::formatVector(Base::Vector3d vec)
{
QString data = QStringLiteral("[%1 %2 %3]")
.arg(QLocale().toString(vec.x, 'f', 2),
QLocale().toString(vec.y, 'f', 2),
QLocale().toString(vec.z, 'f', 2));
return data;
}
void TaskProjGroup::saveButtons(QPushButton* btnOK,
QPushButton* btnCancel)
{
m_btnOK = btnOK;
m_btnCancel = btnCancel;
}
bool TaskProjGroup::apply()
{
if (multiView) {
multiView->recomputeChildren();
}
view->recomputeFeature();
return true;
}
bool TaskProjGroup::accept()
{
Gui::Document* doc = Gui::Application::Instance->getDocument(m_page->getDocument());
if (!doc) {
return false;
}
auto viewCheck = m_page->getDocument()->getObject(m_viewName.c_str());
if (!viewCheck) {
// view has been deleted while this dialog is open
return false;
}
if (multiView) {
multiView->recomputeChildren();
}
view->recomputeFeature();
Gui::Command::doCommand(Gui::Command::Gui, "Gui.ActiveDocument.resetEdit()");
return true;
}
bool TaskProjGroup::reject()
{
Gui::Document* doc = Gui::Application::Instance->getDocument(m_page->getDocument());
if (!doc) {
return false;
}
auto viewCheck = m_page->getDocument()->getObject(m_viewName.c_str());
if (!viewCheck) {
// view has been deleted while this dialog is open
return false;
}
if (getCreateMode()) {
//remove the object completely from the document
const char* viewName = view->getNameInDocument();
const char* PageName = view->findParentPage()->getNameInDocument();
if (multiView) {
Gui::Command::doCommand(Gui::Command::Gui, "App.activeDocument().%s.purgeProjections()",
viewName);
Gui::Command::doCommand(Gui::Command::Gui, "App.activeDocument().%s.removeView(App.activeDocument().%s)",
PageName, viewName);
}
Gui::Command::doCommand(Gui::Command::Gui, "App.activeDocument().removeObject('%s')", viewName);
Gui::Command::doCommand(Gui::Command::Gui, "Gui.ActiveDocument.resetEdit()");
}
else {
//set the DPG and its views back to entry state.
if (Gui::Command::hasPendingCommand()) {
Gui::Command::abortCommand();
}
// Restore views to initial spacing
if (multiView) {
multiView->autoPositionChildren();
}
}
Gui::Command::runCommand(Gui::Command::Gui, "Gui.ActiveDocument.resetEdit()");
return false;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TODO: Do we really need to hang on to the TaskDlgProjGroup in this class? IR
TaskDlgProjGroup::TaskDlgProjGroup(TechDraw::DrawView* featView, bool mode)
: viewProvider(nullptr)
, view(featView)
{
//viewProvider = dynamic_cast<const ViewProviderDrawingView *>(featView);
widget = new TaskProjGroup(featView, mode);
taskbox = new Gui::TaskView::TaskBox(Gui::BitmapFactory().pixmap("actions/TechDraw_ProjectionGroup"),
widget->windowTitle(), true, nullptr);
taskbox->groupLayout()->addWidget(widget);
Content.push_back(taskbox);
}
void TaskDlgProjGroup::update()
{
widget->updateTask();
}
void TaskDlgProjGroup::setCreateMode(bool mode)
{
widget->setCreateMode(mode);
}
void TaskDlgProjGroup::modifyStandardButtons(QDialogButtonBox* box)
{
QPushButton* btnOK = box->button(QDialogButtonBox::Ok);
QPushButton* btnCancel = box->button(QDialogButtonBox::Cancel);
widget->saveButtons(btnOK, btnCancel);
}
//==== calls from the TaskView ===============================================================
void TaskDlgProjGroup::open()
{
if (!widget->getCreateMode()) { //this is an edit session, start a transaction
if (dynamic_cast<TechDraw::DrawProjGroup*>(view)) {
App::GetApplication().setActiveTransaction("Edit Projection Group", true);
}
else {
App::GetApplication().setActiveTransaction("Edit Part View", true);
}
}
}
void TaskDlgProjGroup::clicked(int i)
{
// Q_UNUSED(i);
if (i == QMessageBox::Apply) {
widget->apply();
}
}
bool TaskDlgProjGroup::accept()
{
widget->accept();
return true;
}
bool TaskDlgProjGroup::reject()
{
widget->reject();
return true;
}
DirectionEditDialog::DirectionEditDialog(QWidget* parent) : QDialog(parent) {
setWindowFlags(Qt::Popup); // Make the dialog non-intrusive
createUI();
}
void DirectionEditDialog::setDirection(const Base::Vector3d& pos) {
xSpinBox->setValue(pos.x);
ySpinBox->setValue(pos.y);
zSpinBox->setValue(pos.z);
}
Base::Vector3d DirectionEditDialog::getDirection() const {
return Base::Vector3d(xSpinBox->value().getValue(), ySpinBox->value().getValue(), zSpinBox->value().getValue());
}
void DirectionEditDialog::setAngle(double val) {
angleSpinBox->setValue(val);
}
double DirectionEditDialog::getAngle() const {
return angleSpinBox->value().getValue();
}
void DirectionEditDialog::showEvent(QShowEvent* event) {
QDialog::showEvent(event);
// Calculate the position to ensure the dialog appears within the screen boundaries
QPoint cursorPos = QCursor::pos();
QSize screenSize = QApplication::primaryScreen()->size(); // Get the size of the primary screen
int x = cursorPos.x();
int y = cursorPos.y();
int dialogWidth = this->width();
int dialogHeight = this->height();
// Check if the dialog goes beyond the right edge of the screen
if (x + dialogWidth > screenSize.width()) {
x = screenSize.width() - dialogWidth;
}
// Check if the dialog goes beyond the bottom edge of the screen
if (y + dialogHeight > screenSize.height()) {
y = screenSize.height() - dialogHeight;
}
// Move the dialog to the calculated position
this->move(x, y);
}
void DirectionEditDialog::createUI() {
auto* directionGroup = new QGroupBox(tr("Direction"));
auto* directionLayout = new QVBoxLayout; // Use QVBoxLayout for vertical alignment
// Create layout and widgets for X
auto* xLayout = new QHBoxLayout;
auto* xLabel = new QLabel(QStringLiteral("X: "));
xSpinBox = new Gui::QuantitySpinBox;
xSpinBox->setUnit(Base::Unit::Length);
xLayout->addWidget(xLabel);
xLayout->addWidget(xSpinBox);
// Create layout and widgets for Y
auto* yLayout = new QHBoxLayout;
auto* yLabel = new QLabel(QStringLiteral("Y: "));
ySpinBox = new Gui::QuantitySpinBox;
ySpinBox->setUnit(Base::Unit::Length);
yLayout->addWidget(yLabel);
yLayout->addWidget(ySpinBox);
// Create layout and widgets for Z
auto* zLayout = new QHBoxLayout;
auto* zLabel = new QLabel(QStringLiteral("Z: "));
zSpinBox = new Gui::QuantitySpinBox;
zSpinBox->setUnit(Base::Unit::Length);
zLayout->addWidget(zLabel);
zLayout->addWidget(zSpinBox);
// Add the layouts to the direction group
directionLayout->addLayout(xLayout);
directionLayout->addLayout(yLayout);
directionLayout->addLayout(zLayout);
directionGroup->setLayout(directionLayout);
angleSpinBox = new Gui::QuantitySpinBox;
angleSpinBox->setUnit(Base::Unit::Angle);
auto* buttonsLayout = new QHBoxLayout;
auto* okButton = new QPushButton(tr("OK"));
auto* cancelButton = new QPushButton(tr("Cancel"));
buttonsLayout->addWidget(okButton);
buttonsLayout->addWidget(cancelButton);
auto* mainLayout = new QVBoxLayout;
mainLayout->addWidget(directionGroup);
mainLayout->addWidget(new QLabel(tr("Rotate by")));
mainLayout->addWidget(angleSpinBox);
mainLayout->addLayout(buttonsLayout);
setLayout(mainLayout);
connect(okButton, &QPushButton::clicked, this, &QDialog::accept);
connect(cancelButton, &QPushButton::clicked, this, &QDialog::reject);
}
#include <Mod/TechDraw/Gui/moc_TaskProjGroup.cpp>