Files
create/src/Mod/Sketcher/Gui/EditDatumDialog.cpp
Ladislav Michl 913c30429c Base: Quantity: use isDimensionless whenever feasible
Quantity is often queried for Unit just to see if it has a dimension.
Ask Quantity directly using isDimensionless() method and modify that
method not to care about Quantity value validity; no user was ever
asking for value validity.
2025-06-03 09:31:38 +02:00

322 lines
12 KiB
C++

/***************************************************************************
* Copyright (c) 2011 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* 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 "PreCompiled.h"
#ifndef _PreComp_
/// Qt Include Files
#include <Inventor/sensors/SoSensor.h>
#include <QApplication>
#include <QDialog>
#endif
#include <Base/Tools.h>
#include <Gui/Application.h>
#include <Gui/CommandT.h>
#include <Gui/Document.h>
#include <Gui/MainWindow.h>
#include <Gui/Notifications.h>
#include <Gui/View3DInventor.h>
#include <Gui/View3DInventorViewer.h>
#include <Mod/Sketcher/App/GeometryFacade.h>
#include <Mod/Sketcher/App/SketchObject.h>
#include "EditDatumDialog.h"
#include "Utils.h"
#include "ViewProviderSketch.h"
#include "ui_InsertDatum.h"
using namespace SketcherGui;
/* TRANSLATOR SketcherGui::EditDatumDialog */
bool SketcherGui::checkConstraintName(const Sketcher::SketchObject* sketch,
std::string constraintName)
{
if (constraintName != Base::Tools::getIdentifier(constraintName)) {
Gui::NotifyUserError(
sketch,
QT_TRANSLATE_NOOP("Notifications", "Value Error"),
QT_TRANSLATE_NOOP("Notifications",
"Invalid constraint name (must only contain alphanumericals and "
"underscores, and must not start with digit)"));
return false;
}
return true;
}
EditDatumDialog::EditDatumDialog(ViewProviderSketch* vp, int ConstrNbr)
: ConstrNbr(ConstrNbr)
, success(false)
{
sketch = vp->getSketchObject();
const std::vector<Sketcher::Constraint*>& Constraints = sketch->Constraints.getValues();
Constr = Constraints[ConstrNbr];
}
EditDatumDialog::EditDatumDialog(Sketcher::SketchObject* pcSketch, int ConstrNbr)
: sketch(pcSketch)
, ConstrNbr(ConstrNbr)
{
const std::vector<Sketcher::Constraint*>& Constraints = sketch->Constraints.getValues();
Constr = Constraints[ConstrNbr];
}
EditDatumDialog::~EditDatumDialog()
{}
int EditDatumDialog::exec(bool atCursor)
{
// Return if constraint doesn't have editable value
if (Constr->isDimensional()) {
if (sketch->hasConflicts()) {
Gui::TranslatedUserWarning(sketch,
QObject::tr("Dimensional constraint"),
QObject::tr("Not allowed to edit the datum because the "
"sketch contains conflicting constraints"));
return QDialog::Rejected;
}
Base::Quantity init_val;
QDialog dlg(Gui::getMainWindow());
if (!ui_ins_datum) {
ui_ins_datum.reset(new Ui_InsertDatum);
ui_ins_datum->setupUi(&dlg);
}
double datum = Constr->getValue();
ui_ins_datum->labelEdit->setEntryName(QByteArray("DatumValue"));
if (Constr->Type == Sketcher::Angle) {
datum = Base::toDegrees<double>(datum);
dlg.setWindowTitle(tr("Insert angle"));
init_val.setUnit(Base::Unit::Angle);
ui_ins_datum->label->setText(tr("Angle:"));
ui_ins_datum->labelEdit->setParamGrpPath(
QByteArray("User parameter:BaseApp/History/SketcherAngle"));
}
else if (Constr->Type == Sketcher::Radius) {
dlg.setWindowTitle(tr("Insert radius"));
init_val.setUnit(Base::Unit::Length);
ui_ins_datum->label->setText(tr("Radius:"));
ui_ins_datum->labelEdit->setParamGrpPath(
QByteArray("User parameter:BaseApp/History/SketcherLength"));
}
else if (Constr->Type == Sketcher::Diameter) {
dlg.setWindowTitle(tr("Insert diameter"));
init_val.setUnit(Base::Unit::Length);
ui_ins_datum->label->setText(tr("Diameter:"));
ui_ins_datum->labelEdit->setParamGrpPath(
QByteArray("User parameter:BaseApp/History/SketcherLength"));
}
else if (Constr->Type == Sketcher::Weight) {
dlg.setWindowTitle(tr("Insert weight"));
ui_ins_datum->label->setText(tr("Weight:"));
ui_ins_datum->labelEdit->setParamGrpPath(
QByteArray("User parameter:BaseApp/History/SketcherWeight"));
}
else if (Constr->Type == Sketcher::SnellsLaw) {
dlg.setWindowTitle(tr("Refractive index ratio", "Constraint_SnellsLaw"));
ui_ins_datum->label->setText(tr("Ratio n2/n1:", "Constraint_SnellsLaw"));
ui_ins_datum->labelEdit->setParamGrpPath(
QByteArray("User parameter:BaseApp/History/SketcherRefrIndexRatio"));
ui_ins_datum->labelEdit->setSingleStep(0.05);
}
else {
dlg.setWindowTitle(tr("Insert length"));
init_val.setUnit(Base::Unit::Length);
ui_ins_datum->label->setText(tr("Length:"));
ui_ins_datum->labelEdit->setParamGrpPath(
QByteArray("User parameter:BaseApp/History/SketcherLength"));
}
init_val.setValue(datum);
ui_ins_datum->labelEdit->setValue(init_val);
ui_ins_datum->labelEdit->pushToHistory();
ui_ins_datum->labelEdit->selectNumber();
ui_ins_datum->labelEdit->bind(sketch->Constraints.createPath(ConstrNbr));
ui_ins_datum->name->setText(QString::fromStdString(Constr->Name));
ui_ins_datum->cbDriving->setChecked(!Constr->isDriving);
connect(ui_ins_datum->cbDriving,
&QCheckBox::toggled,
this,
&EditDatumDialog::drivingToggled);
connect(ui_ins_datum->labelEdit,
qOverload<const Base::Quantity&>(&Gui::QuantitySpinBox::valueChanged),
this,
&EditDatumDialog::datumChanged);
connect(ui_ins_datum->labelEdit,
&Gui::QuantitySpinBox::showFormulaDialog,
this,
&EditDatumDialog::formEditorOpened);
connect(&dlg, &QDialog::accepted, this, &EditDatumDialog::accepted);
connect(&dlg, &QDialog::rejected, this, &EditDatumDialog::rejected);
if (atCursor) {
dlg.show(); // Need to show the dialog so geometry is computed
QRect pg = dlg.parentWidget()->geometry();
int Xmin = pg.x() + 10;
int Ymin = pg.y() + 10;
int Xmax = pg.x() + pg.width() - dlg.geometry().width() - 10;
int Ymax = pg.y() + pg.height() - dlg.geometry().height() - 10;
int x = Xmax < Xmin ? (Xmin + Xmax) / 2
: std::min(std::max(QCursor::pos().x(), Xmin), Xmax);
int y = Ymax < Ymin ? (Ymin + Ymax) / 2
: std::min(std::max(QCursor::pos().y(), Ymin), Ymax);
dlg.setGeometry(x, y, dlg.geometry().width(), dlg.geometry().height());
}
return dlg.exec();
}
return QDialog::Rejected;
}
void EditDatumDialog::accepted()
{
Base::Quantity newQuant = ui_ins_datum->labelEdit->value();
if (Constr->Type == Sketcher::SnellsLaw || Constr->Type == Sketcher::Weight
|| !newQuant.isDimensionless()) {
// save the value for the history
ui_ins_datum->labelEdit->pushToHistory();
double newDatum = newQuant.getValue();
try {
/*if (ui_ins_datum->cbDriving->isChecked() == Constr->isDriving) {
Gui::cmdAppObjectArgs(sketch, "toggleDriving(%i)", ConstrNbr);
}*/
if (!ui_ins_datum->cbDriving->isChecked()) {
if (ui_ins_datum->labelEdit->hasExpression()) {
ui_ins_datum->labelEdit->apply();
}
else {
auto unitString = newQuant.getUnit().getString();
unitString = Base::Tools::escapeQuotesFromString(unitString);
Gui::cmdAppObjectArgs(sketch,
"setDatum(%i,App.Units.Quantity('%f %s'))",
ConstrNbr,
newDatum,
unitString);
}
}
std::string constraintName = ui_ins_datum->name->text().trimmed().toStdString();
std::string currConstraintName = sketch->Constraints[ConstrNbr]->Name;
if (constraintName != currConstraintName) {
if (!SketcherGui::checkConstraintName(sketch, constraintName)) {
constraintName = currConstraintName;
}
Gui::cmdAppObjectArgs(sketch,
"renameConstraint(%d, u'%s')",
ConstrNbr,
constraintName.c_str());
}
Gui::Command::commitCommand();
// THIS IS A WORK-AROUND NOT TO DELAY 0.19 RELEASE
//
// depsAreTouched is not returning true in this case:
// https://forum.freecad.org/viewtopic.php?f=3&t=55633&p=481061#p478477
//
// It appears related to a drastic change in how dependencies are calculated, see:
// https://forum.freecad.org/viewtopic.php?f=3&t=55633&p=481061#p481061
//
// This is NOT the solution, as there is no point in systematically executing the
// ExpressionEngine on every dimensional constraint change. Just a quick fix to avoid
// clearly unwanted behaviour in absence of time to actually fix the root cause.
// if (sketch->noRecomputes && sketch->ExpressionEngine.depsAreTouched()) {
sketch->ExpressionEngine.execute();
sketch->solve();
//}
tryAutoRecompute(sketch);
success = true;
}
catch (const Base::Exception& e) {
Gui::NotifyUserError(sketch,
QT_TRANSLATE_NOOP("Notifications", "Value Error"),
e.what());
Gui::Command::abortCommand();
if (sketch->noRecomputes) { // if setdatum failed, it is highly likely that solver
// information is invalid.
sketch->solve();
}
}
}
}
void EditDatumDialog::rejected()
{
Gui::Command::abortCommand();
sketch->recomputeFeature();
}
bool EditDatumDialog::isSuccess()
{
return success;
}
void EditDatumDialog::drivingToggled(bool state)
{
if (state) {
ui_ins_datum->labelEdit->setToLastUsedValue();
}
sketch->setDriving(ConstrNbr, !state);
if (!sketch->noRecomputes) { // if noRecomputes, solve() is already done by setDriving()
sketch->solve();
}
}
void EditDatumDialog::datumChanged()
{
if (ui_ins_datum->labelEdit->text()
!= std::as_const(ui_ins_datum->labelEdit)->getHistory()[0]) {
ui_ins_datum->cbDriving->setChecked(false);
}
}
void EditDatumDialog::formEditorOpened(bool state)
{
if (state) {
ui_ins_datum->cbDriving->setChecked(false);
}
}
#include "moc_EditDatumDialog.cpp"