Compare commits
99 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6530e36418 | |||
| c5eca93a20 | |||
| e2fd673287 | |||
| 45e1973680 | |||
| e97f4985c8 | |||
| f29d8d8dde | |||
| 73ed43d2c1 | |||
| 4bec2964ed | |||
| be674c362b | |||
| 6ca055d277 | |||
| 3daf116fdf | |||
| 951cb89046 | |||
| b8753a8ede | |||
| 0f1ab68e88 | |||
| b33324a5df | |||
| bea3c220ca | |||
| 08880ec7aa | |||
| 7ef83f9d4d | |||
| 5534bd375a | |||
| 765d7f708d | |||
| f069150ef5 | |||
| 68384f549c | |||
| af2e83e06b | |||
| 999423cd74 | |||
| f924551620 | |||
| 27cc2b2a65 | |||
| 6d334db42c | |||
| 6a441fea8d | |||
| 7622933a16 | |||
| d292788097 | |||
| c5d0acce8a | |||
| b2206d81f3 | |||
| ee5b201b1e | |||
| 1ecd012a02 | |||
| dab2d652ac | |||
| c8109c9401 | |||
| 39da720c8a | |||
| eaf5814778 | |||
| da51b0be53 | |||
| bba3a23405 | |||
| e6673d60ad | |||
| f1e4cb4433 | |||
| db2d518aa2 | |||
| 0d3c05447a | |||
| 9ed2c3570c | |||
| abe65e7a75 | |||
| 781cb10a7d | |||
| 99d6dd7c5b | |||
| e2173e88f4 | |||
| 5cfb3ce018 | |||
| 597b3b6ba0 | |||
| 5007a72eaa | |||
| e2e002ea27 | |||
| a8270021ee | |||
| 24550b0ccf | |||
| c9ab285c61 | |||
| 31b8344d73 | |||
| 0f303a785b | |||
| 51ea0ed9e6 | |||
| 9989a2ef4a | |||
| 2b9894f3a9 | |||
| 76c7f52543 | |||
| de7cba4669 | |||
| 1f024523e6 | |||
| 6989306097 | |||
| 211d74f4a6 | |||
| eafe6b73ec | |||
| 1eb65aa002 | |||
| 969c1eee2d | |||
| c974f914db | |||
| 5a7a2d2f81 | |||
| 312d8299cb | |||
| 257d22e1e0 | |||
| a43995fc45 | |||
| 0988177e62 | |||
| 7b5e18a075 | |||
| ed87d3aceb | |||
| 133ef7173d | |||
| 8e7a8b1e7b | |||
| b3abe32683 | |||
| 53b4eb0b2e | |||
| 51855e5341 | |||
| 12055a22d8 | |||
| 6f67fbc425 | |||
| 83e308c8eb | |||
| de1d0acaea | |||
| e239684102 | |||
| aedd1f96e4 | |||
| e7c796edb4 | |||
| 6858586642 | |||
| a88db11e0a | |||
| f4574cf02d | |||
| 159a71bba7 | |||
| dfc3e2b9a6 | |||
| 27b568e4e4 | |||
| a266852510 | |||
| 408128838c | |||
| fc0c1069d2 | |||
| 5ea583466d |
@@ -0,0 +1,43 @@
|
||||
# gitlab CI config file
|
||||
|
||||
# this image is on dockerhub. Dockerfile is here: https://gitlab.com/PrzemoF/FreeCAD/-/blob/gitlab-v1/ci/Dockerfile
|
||||
image: freecadci/runner
|
||||
|
||||
stages: # List of stages for jobs, and their order of execution
|
||||
- build
|
||||
- test
|
||||
|
||||
before_script:
|
||||
- apt-get update -yqq
|
||||
# CCache Config
|
||||
- mkdir -p ccache
|
||||
- export CCACHE_BASEDIR=${PWD}
|
||||
- export CCACHE_DIR=${PWD}/ccache
|
||||
|
||||
cache:
|
||||
paths:
|
||||
- ccache/
|
||||
|
||||
build-job: # This job runs in the build stage, which runs first.
|
||||
stage: build
|
||||
|
||||
script:
|
||||
- echo "Compiling the code..."
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ccache cmake -DBUILD_QT5=1 ../
|
||||
- ccache cmake --build ./ -j$(nproc)
|
||||
- echo "Compile complete."
|
||||
|
||||
artifacts:
|
||||
paths:
|
||||
- build/
|
||||
|
||||
test-job: # This job runs in the test stage.
|
||||
stage: test # It only starts when the job in the build stage completes successfully.
|
||||
script:
|
||||
- echo "Running unit tests... "
|
||||
- cd build/bin/
|
||||
# Testing currently doesn't work due to problems with libraries ot being visible by the binary.
|
||||
- ./FreeCADCmd -t 0
|
||||
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
FROM ubuntu:20.04
|
||||
MAINTAINER Przemo Firszt
|
||||
# This is the docker image definition used to build FreeCAD. It's currently accessible on:
|
||||
# https://hub.docker.com/repository/docker/freecadci/runner
|
||||
# on under name freecadci/runner when using docker
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN apt-get update -y
|
||||
RUN apt-get update -y && apt-get install -y gnupg2
|
||||
RUN echo "deb http://ppa.launchpad.net/freecad-maintainers/freecad-daily/ubuntu focal main" >> /etc/apt/sources.list.d/freecad-daily.list
|
||||
RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 83193AA3B52FF6FCF10A1BBF005EAE8119BB5BCA
|
||||
RUN apt-get update -y
|
||||
|
||||
# those 3 are for debugging purposes only. Not required to build FreeCAD
|
||||
RUN apt-get install -y \
|
||||
vim \
|
||||
nano \
|
||||
bash
|
||||
|
||||
# Main set of FreeCAD dependencies. To be verified.
|
||||
RUN apt-get install -y \
|
||||
ccache \
|
||||
cmake \
|
||||
debhelper \
|
||||
dh-exec \
|
||||
dh-python \
|
||||
doxygen \
|
||||
git \
|
||||
graphviz \
|
||||
libboost-date-time-dev \
|
||||
libboost-dev \
|
||||
libboost-filesystem-dev \
|
||||
libboost-filesystem1.71-dev \
|
||||
libboost-graph-dev \
|
||||
libboost-iostreams-dev \
|
||||
libboost-program-options-dev \
|
||||
libboost-program-options1.71-dev \
|
||||
libboost-python1.71-dev \
|
||||
libboost-regex-dev \
|
||||
libboost-regex1.71-dev \
|
||||
libboost-serialization-dev \
|
||||
libboost-system1.71-dev \
|
||||
libboost-thread-dev \
|
||||
libboost-thread1.71-dev \
|
||||
libboost1.71-dev \
|
||||
libcoin-dev \
|
||||
libdouble-conversion-dev \
|
||||
libeigen3-dev \
|
||||
libglew-dev \
|
||||
libgts-bin \
|
||||
libgts-dev \
|
||||
libkdtree++-dev \
|
||||
liblz4-dev \
|
||||
libmedc-dev \
|
||||
libmetis-dev \
|
||||
libnglib-dev \
|
||||
libocct-data-exchange-dev \
|
||||
libocct-ocaf-dev \
|
||||
libocct-visualization-dev \
|
||||
libopencv-dev \
|
||||
libproj-dev \
|
||||
libpyside2-dev \
|
||||
libqt5opengl5 \
|
||||
libqt5opengl5-dev \
|
||||
libqt5svg5-dev \
|
||||
libqt5webkit5 \
|
||||
libqt5webkit5-dev \
|
||||
libqt5x11extras5-dev \
|
||||
libqt5xmlpatterns5-dev \
|
||||
libshiboken2-dev \
|
||||
libspnav-dev \
|
||||
libvtk7-dev \
|
||||
libvtk7.1p \
|
||||
libvtk7.1p-qt \
|
||||
libx11-dev \
|
||||
libxerces-c-dev \
|
||||
libzipios++-dev \
|
||||
lsb-release \
|
||||
nastran \
|
||||
netgen \
|
||||
netgen-headers \
|
||||
occt-draw \
|
||||
pybind11-dev \
|
||||
pyqt5-dev-tools \
|
||||
pyside2-tools \
|
||||
python3-dev \
|
||||
python3-matplotlib \
|
||||
python3-pivy \
|
||||
python3-ply \
|
||||
python3-pyqt5 \
|
||||
python3-pyside2.* \
|
||||
python3-pyside2.qtcore \
|
||||
python3-pyside2.qtgui \
|
||||
python3-pyside2.qtsvg \
|
||||
python3-pyside2.qtuitools \
|
||||
python3-pyside2.qtwidgets \
|
||||
python3-pyside2.qtxml \
|
||||
python3-requests \
|
||||
python3-yaml \
|
||||
qt5-default \
|
||||
qt5-qmake \
|
||||
qtbase5-dev \
|
||||
qttools5-dev \
|
||||
qtwebengine5-dev \
|
||||
swig
|
||||
|
||||
RUN apt-get update -y --fix-missing
|
||||
|
||||
# Clean
|
||||
RUN apt-get clean \
|
||||
&& rm /var/lib/apt/lists/* \
|
||||
/usr/share/doc/* \
|
||||
/usr/share/locale/* \
|
||||
/usr/share/man/* \
|
||||
/usr/share/info/* -fR
|
||||
|
||||
|
||||
@@ -2398,8 +2398,8 @@ private:
|
||||
|
||||
Base::FileInfo tmp(sourcename);
|
||||
if (tmp.renameFile(targetname.c_str()) == false) {
|
||||
Base::Console().Warning("Cannot rename file from '%s' to '%s'\n",
|
||||
sourcename.c_str(), targetname.c_str());
|
||||
throw Base::FileException(
|
||||
"Cannot rename tmp save file to project file", targetname);
|
||||
}
|
||||
}
|
||||
void applyTimeStamp(const std::string& sourcename, const std::string& targetname) {
|
||||
@@ -2531,9 +2531,8 @@ private:
|
||||
|
||||
Base::FileInfo tmp(sourcename);
|
||||
if (tmp.renameFile(targetname.c_str()) == false) {
|
||||
Base::Console().Error("Save interrupted: Cannot rename file from '%s' to '%s'\n",
|
||||
sourcename.c_str(), targetname.c_str());
|
||||
//throw Base::FileException("Save interrupted: Cannot rename temporary file to project file", tmp);
|
||||
throw Base::FileException(
|
||||
"Save interrupted: Cannot rename temporary file to project file", tmp);
|
||||
}
|
||||
|
||||
if (numberOfFiles <= 0) {
|
||||
|
||||
@@ -38,6 +38,7 @@ Enumeration::Enumeration()
|
||||
}
|
||||
|
||||
Enumeration::Enumeration(const Enumeration &other)
|
||||
: _EnumArray(NULL), _ownEnumArray(false), _index(0), _maxVal(-1)
|
||||
{
|
||||
if (other._ownEnumArray) {
|
||||
setEnums(other.getEnumVector());
|
||||
|
||||
@@ -56,7 +56,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
<hr>
|
||||
|
||||
<h3><a name="_TocCoin3D"></a>Coin3D</h3>
|
||||
<p>Web site: <a href="https://bitbucket.org/Coin3D/coin/">https://bitbucket.org/Coin3D/coin/</a></p>
|
||||
<p>Web site: <a href="https://coin3d.github.io">https://coin3d.github.io</a></p>
|
||||
<p>Copyright: Coin is copyright (C) 1998-2013 Kongsberg Oil & Gas Technologies AS</p>
|
||||
<p>License: BSD-3-clause</p>
|
||||
<pre>
|
||||
|
||||
@@ -1937,6 +1937,9 @@ void Application::runApplication(void)
|
||||
else {
|
||||
// Enable automatic scaling based on pixel density of display (added in Qt 5.6)
|
||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
|
||||
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
||||
#endif
|
||||
}
|
||||
#endif // QT_VERSION >= 0x050600
|
||||
|
||||
@@ -1954,6 +1957,20 @@ void Application::runApplication(void)
|
||||
}
|
||||
#endif // QT_VERSION >= 0x050400
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
|
||||
// By default (on platforms that support it, see docs for
|
||||
// Qt::AA_CompressHighFrequencyEvents) QT applies compression
|
||||
// for high frequency events (mouse move, touch, window resizes)
|
||||
// to keep things smooth even when handling the event takes a
|
||||
// while (e.g. to calculate snapping).
|
||||
// However, tablet pen move events (and mouse move events
|
||||
// synthesised from those) are not compressed by default (to
|
||||
// allow maximum precision when e.g. hand-drawing curves),
|
||||
// leading to unacceptable slowdowns using a tablet pen. Enable
|
||||
// compression for tablet events here to solve that.
|
||||
QCoreApplication::setAttribute(Qt::AA_CompressTabletEvents);
|
||||
#endif
|
||||
|
||||
// A new QApplication
|
||||
Base::Console().Log("Init: Creating Gui::Application and QApplication\n");
|
||||
|
||||
|
||||
@@ -220,6 +220,9 @@
|
||||
<property name="toolTip">
|
||||
<string>The directory in which the application will search for macros</string>
|
||||
</property>
|
||||
<property name="mode">
|
||||
<enum>Gui::FileChooser::Directory</enum>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>MacroPath</cstring>
|
||||
</property>
|
||||
|
||||
@@ -58,10 +58,10 @@ void DlgSettingsSelection::saveSettings()
|
||||
void DlgSettingsSelection::loadSettings()
|
||||
{
|
||||
auto handle = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/TreeView");
|
||||
ui->checkBoxAutoSwitch->setChecked(handle->GetBool("SyncView"));
|
||||
ui->checkBoxAutoExpand->setChecked(handle->GetBool("SyncSelection"));
|
||||
ui->checkBoxPreselect->setChecked(handle->GetBool("PreSelection"));
|
||||
ui->checkBoxRecord->setChecked(handle->GetBool("RecordSelection"));
|
||||
ui->checkBoxAutoSwitch->setChecked(handle->GetBool("SyncView", true));
|
||||
ui->checkBoxAutoExpand->setChecked(handle->GetBool("SyncSelection", true));
|
||||
ui->checkBoxPreselect->setChecked(handle->GetBool("PreSelection", true));
|
||||
ui->checkBoxRecord->setChecked(handle->GetBool("RecordSelection", true));
|
||||
ui->checkBoxSelectionCheckBoxes->setChecked(handle->GetBool("CheckBoxesSelection"));
|
||||
}
|
||||
|
||||
|
||||
@@ -1161,6 +1161,7 @@ bool Document::save(void)
|
||||
catch (const Base::Exception& e) {
|
||||
QMessageBox::critical(getMainWindow(), QObject::tr("Saving document failed"),
|
||||
QString::fromLatin1(e.what()));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -59,6 +59,13 @@ bool ExpressionBinding::isBound() const
|
||||
return path.getDocumentObject() != 0;
|
||||
}
|
||||
|
||||
void ExpressionBinding::unbind()
|
||||
{
|
||||
expressionchanged.disconnect();
|
||||
objectdeleted.disconnect();
|
||||
path = App::ObjectIdentifier();
|
||||
}
|
||||
|
||||
void Gui::ExpressionBinding::setExpression(boost::shared_ptr<Expression> expr)
|
||||
{
|
||||
DocumentObject * docObj = path.getDocumentObject();
|
||||
@@ -100,7 +107,11 @@ void ExpressionBinding::bind(const App::ObjectIdentifier &_path)
|
||||
|
||||
//connect to be informed about changes
|
||||
DocumentObject * docObj = path.getDocumentObject();
|
||||
connection = docObj->ExpressionEngine.expressionChanged.connect(boost::bind(&ExpressionBinding::expressionChange, this, bp::_1));
|
||||
if (docObj) {
|
||||
expressionchanged = docObj->ExpressionEngine.expressionChanged.connect(boost::bind(&ExpressionBinding::expressionChange, this, bp::_1));
|
||||
App::Document* doc = docObj->getDocument();
|
||||
objectdeleted = doc->signalDeletedObject.connect(boost::bind(&ExpressionBinding::objectDeleted, this, bp::_1));
|
||||
}
|
||||
}
|
||||
|
||||
void ExpressionBinding::bind(const Property &prop)
|
||||
@@ -247,3 +258,11 @@ void ExpressionBinding::expressionChange(const ObjectIdentifier& id) {
|
||||
if(id==path)
|
||||
onChange();
|
||||
}
|
||||
|
||||
void ExpressionBinding::objectDeleted(const App::DocumentObject& obj)
|
||||
{
|
||||
DocumentObject * docObj = path.getDocumentObject();
|
||||
if (docObj == &obj) {
|
||||
unbind();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ public:
|
||||
virtual void bind(const App::ObjectIdentifier & _path);
|
||||
virtual void bind(const App::Property & prop);
|
||||
bool isBound() const;
|
||||
void unbind();
|
||||
virtual bool apply(const std::string &propName);
|
||||
virtual bool apply();
|
||||
bool hasExpression() const;
|
||||
@@ -52,8 +53,8 @@ public:
|
||||
|
||||
//auto apply means that the python code is issued not only on apply() but
|
||||
//also on setExpression
|
||||
bool autoApply() const {return m_autoApply;};
|
||||
void setAutoApply(bool value) {m_autoApply = value;};
|
||||
bool autoApply() const {return m_autoApply;}
|
||||
void setAutoApply(bool value) {m_autoApply = value;}
|
||||
|
||||
protected:
|
||||
const App::ObjectIdentifier & getPath() const { return path; }
|
||||
@@ -63,7 +64,7 @@ protected:
|
||||
virtual void setExpression(boost::shared_ptr<App::Expression> expr);
|
||||
|
||||
//gets called when the bound expression is changed, either by this binding or any external action
|
||||
virtual void onChange() {};
|
||||
virtual void onChange() {}
|
||||
|
||||
private:
|
||||
App::ObjectIdentifier path;
|
||||
@@ -75,7 +76,9 @@ protected:
|
||||
int iconHeight;
|
||||
|
||||
void expressionChange(const App::ObjectIdentifier& id);
|
||||
boost::signals2::scoped_connection connection;
|
||||
void objectDeleted(const App::DocumentObject&);
|
||||
boost::signals2::scoped_connection expressionchanged;
|
||||
boost::signals2::scoped_connection objectdeleted;
|
||||
bool m_autoApply;
|
||||
};
|
||||
|
||||
|
||||
@@ -33,8 +33,10 @@
|
||||
# include <QSvgRenderer>
|
||||
# include <QGraphicsSvgItem>
|
||||
# include <QMessageBox>
|
||||
# include <QMouseEvent>
|
||||
# include <QGraphicsScene>
|
||||
# include <QGraphicsView>
|
||||
# include <QScrollBar>
|
||||
# include <QThread>
|
||||
# include <QProcess>
|
||||
# include <boost_bind_bind.hpp>
|
||||
@@ -146,6 +148,92 @@ private:
|
||||
QByteArray str, flatStr;
|
||||
};
|
||||
|
||||
// Simple wrapper around QGraphicsView to make panning possible
|
||||
class GraphvizGraphicsView final : public QGraphicsView
|
||||
{
|
||||
public:
|
||||
GraphvizGraphicsView(QGraphicsScene* scene, QWidget* parent);
|
||||
~GraphvizGraphicsView() = default;
|
||||
|
||||
GraphvizGraphicsView(const GraphvizGraphicsView&) = delete;
|
||||
GraphvizGraphicsView(GraphvizGraphicsView&&) = delete;
|
||||
GraphvizGraphicsView& operator=(const GraphvizGraphicsView&) = delete;
|
||||
GraphvizGraphicsView& operator=(GraphvizGraphicsView&&) = delete;
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
|
||||
private:
|
||||
bool isPanning;
|
||||
QPoint panStart;
|
||||
};
|
||||
|
||||
GraphvizGraphicsView::GraphvizGraphicsView(QGraphicsScene* scene, QWidget* parent) : QGraphicsView(scene, parent),
|
||||
isPanning(false)
|
||||
{
|
||||
}
|
||||
|
||||
void GraphvizGraphicsView::mousePressEvent(QMouseEvent* e)
|
||||
{
|
||||
if(e && e->button() == Qt::LeftButton)
|
||||
{
|
||||
isPanning = true;
|
||||
panStart = e->pos();
|
||||
e->accept();
|
||||
QApplication::setOverrideCursor(Qt::ClosedHandCursor);
|
||||
}
|
||||
|
||||
QGraphicsView::mousePressEvent(e);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void GraphvizGraphicsView::mouseMoveEvent(QMouseEvent *e)
|
||||
{
|
||||
if(e == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(isPanning)
|
||||
{
|
||||
auto* horizontalScrollbar = horizontalScrollBar();
|
||||
auto* verticalScrollbar = verticalScrollBar();
|
||||
if(horizontalScrollbar == nullptr ||
|
||||
verticalScrollbar == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto direction = e->pos() - panStart;
|
||||
horizontalScrollbar->setValue(horizontalScrollbar->value() - direction.x());
|
||||
verticalScrollbar->setValue(verticalScrollbar->value() - direction.y());
|
||||
|
||||
panStart = e->pos();
|
||||
e->accept();
|
||||
}
|
||||
|
||||
QGraphicsView::mouseMoveEvent(e);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void GraphvizGraphicsView::mouseReleaseEvent(QMouseEvent* e)
|
||||
{
|
||||
if(e && e->button() & Qt::LeftButton)
|
||||
{
|
||||
isPanning = false;
|
||||
QApplication::restoreOverrideCursor();
|
||||
e->accept();
|
||||
}
|
||||
|
||||
QGraphicsView::mouseReleaseEvent(e);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* TRANSLATOR Gui::GraphvizView */
|
||||
@@ -165,7 +253,7 @@ GraphvizView::GraphvizView(App::Document & _doc, QWidget* parent)
|
||||
scene->addItem(svgItem);
|
||||
|
||||
// Create view and zoomer object
|
||||
view = new QGraphicsView(scene, this);
|
||||
view = new GraphvizGraphicsView(scene, this);
|
||||
zoomer = new GraphicsViewZoom(view);
|
||||
zoomer->set_modifiers(Qt::NoModifier);
|
||||
view->show();
|
||||
|
||||
@@ -89,9 +89,6 @@ PropertyView::PropertyView(QWidget *parent)
|
||||
tabs = new QTabWidget (this);
|
||||
tabs->setObjectName(QString::fromUtf8("propertyTab"));
|
||||
tabs->setTabPosition(QTabWidget::South);
|
||||
#if defined(Q_OS_WIN32)
|
||||
tabs->setTabShape(QTabWidget::Triangular);
|
||||
#endif
|
||||
pLayout->addWidget(tabs, 0, 0);
|
||||
|
||||
propertyEditorView = new Gui::PropertyEditor::PropertyEditor();
|
||||
|
||||
@@ -571,14 +571,14 @@ void AboutDialog::showLicenseInformation()
|
||||
// Coin3D
|
||||
li.name = QLatin1String("Coin3D");
|
||||
li.href = baseurl + QLatin1String("#_TocCoin3D");
|
||||
li.url = QLatin1String("https://bitbucket.org/Coin3D/coin/");
|
||||
li.url = QLatin1String("https://coin3d.github.io");
|
||||
li.version = QLatin1String(COIN_VERSION);
|
||||
libInfo << li;
|
||||
|
||||
// Eigen3
|
||||
li.name = QLatin1String("Eigen3");
|
||||
li.href = baseurl + QLatin1String("#_TocEigen3");
|
||||
li.url = QLatin1String("http://eigen.tuxfamily.org/");
|
||||
li.url = QLatin1String("http://eigen.tuxfamily.org");
|
||||
li.version.clear();
|
||||
libInfo << li;
|
||||
|
||||
|
||||
@@ -1552,6 +1552,18 @@ QPushButton:checked {
|
||||
border-color: #65A2E5;
|
||||
}
|
||||
|
||||
/*==================================================================================================
|
||||
Tool button Icon fix in save dialogs
|
||||
==================================================================================================*/
|
||||
/* found under Tools -> Save Picture */ /* Draft -> ShapeString -> Font file */
|
||||
|
||||
QFileDialog#QFileDialog QToolButton {
|
||||
background-color: transparent;
|
||||
padding: 1px;
|
||||
border: 1px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
|
||||
/*==================================================================================================
|
||||
Tool button inside QDialogs that works as QPushButtons
|
||||
|
||||
@@ -1519,6 +1519,18 @@ QPushButton:checked {
|
||||
border-color: #3874f2;
|
||||
}
|
||||
|
||||
/*==================================================================================================
|
||||
Tool button Icon fix in save dialogs
|
||||
==================================================================================================*/
|
||||
/* found under Tools -> Save Picture */ /* Draft -> ShapeString -> Font file */
|
||||
|
||||
QFileDialog#QFileDialog QToolButton {
|
||||
background-color: transparent;
|
||||
padding: 1px;
|
||||
border: 1px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
|
||||
/*==================================================================================================
|
||||
Tool button inside QDialogs that works as QPushButtons
|
||||
|
||||
@@ -1519,6 +1519,18 @@ QPushButton:checked {
|
||||
border-color: #2053c0;
|
||||
}
|
||||
|
||||
/*==================================================================================================
|
||||
Tool button Icon fix in save dialogs
|
||||
==================================================================================================*/
|
||||
/* found under Tools -> Save Picture */ /* Draft -> ShapeString -> Font file */
|
||||
|
||||
QFileDialog#QFileDialog QToolButton {
|
||||
background-color: transparent;
|
||||
padding: 1px;
|
||||
border: 1px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
|
||||
/*==================================================================================================
|
||||
Tool button inside QDialogs that works as QPushButtons
|
||||
|
||||
@@ -1519,6 +1519,17 @@ QPushButton:checked {
|
||||
border-color: #819c0c;
|
||||
}
|
||||
|
||||
/*==================================================================================================
|
||||
Tool button Icon fix in save dialogs
|
||||
==================================================================================================*/
|
||||
/* found under Tools -> Save Picture */ /* Draft -> ShapeString -> Font file */
|
||||
|
||||
QFileDialog#QFileDialog QToolButton {
|
||||
background-color: transparent;
|
||||
padding: 1px;
|
||||
border: 1px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
/*==================================================================================================
|
||||
Tool button inside QDialogs that works as QPushButtons
|
||||
|
||||
@@ -1519,6 +1519,18 @@ QPushButton:checked {
|
||||
border-color: #d0970c;
|
||||
}
|
||||
|
||||
/*==================================================================================================
|
||||
Tool button Icon fix in save dialogs
|
||||
==================================================================================================*/
|
||||
/* found under Tools -> Save Picture */ /* Draft -> ShapeString -> Font file */
|
||||
|
||||
QFileDialog#QFileDialog QToolButton {
|
||||
background-color: transparent;
|
||||
padding: 1px;
|
||||
border: 1px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
|
||||
/*==================================================================================================
|
||||
Tool button inside QDialogs that works as QPushButtons
|
||||
|
||||
@@ -1519,6 +1519,18 @@ QPushButton:checked {
|
||||
border-color: #2053c0;
|
||||
}
|
||||
|
||||
/*==================================================================================================
|
||||
Tool button Icon fix in save dialogs
|
||||
==================================================================================================*/
|
||||
/* found under Tools -> Save Picture */ /* Draft -> ShapeString -> Font file */
|
||||
|
||||
QFileDialog#QFileDialog QToolButton {
|
||||
background-color: transparent;
|
||||
padding: 1px;
|
||||
border: 1px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
|
||||
/*==================================================================================================
|
||||
Tool button inside QDialogs that works as QPushButtons
|
||||
|
||||
@@ -1519,6 +1519,18 @@ QPushButton:checked {
|
||||
border-color: #74831d;
|
||||
}
|
||||
|
||||
/*==================================================================================================
|
||||
Tool button Icon fix in save dialogs
|
||||
==================================================================================================*/
|
||||
/* found under Tools -> Save Picture */ /* Draft -> ShapeString -> Font file */
|
||||
|
||||
QFileDialog#QFileDialog QToolButton {
|
||||
background-color: transparent;
|
||||
padding: 1px;
|
||||
border: 1px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
|
||||
/*==================================================================================================
|
||||
Tool button inside QDialogs that works as QPushButtons
|
||||
|
||||
@@ -1519,6 +1519,18 @@ QPushButton:checked {
|
||||
border-color: #b28416;
|
||||
}
|
||||
|
||||
/*==================================================================================================
|
||||
Tool button Icon fix in save dialogs
|
||||
==================================================================================================*/
|
||||
/* found under Tools -> Save Picture */ /* Draft -> ShapeString -> Font file */
|
||||
|
||||
QFileDialog#QFileDialog QToolButton {
|
||||
background-color: transparent;
|
||||
padding: 1px;
|
||||
border: 1px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
|
||||
/*==================================================================================================
|
||||
Tool button inside QDialogs that works as QPushButtons
|
||||
|
||||
@@ -1516,6 +1516,18 @@ QPushButton:checked {
|
||||
border-color: #3874f2;
|
||||
}
|
||||
|
||||
/*==================================================================================================
|
||||
Tool button Icon fix in save dialogs
|
||||
==================================================================================================*/
|
||||
/* found under Tools -> Save Picture */ /* Draft -> ShapeString -> Font file */
|
||||
|
||||
QFileDialog#QFileDialog QToolButton {
|
||||
background-color: transparent;
|
||||
padding: 1px;
|
||||
border: 1px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
|
||||
/*==================================================================================================
|
||||
Tool button inside QDialogs that works as QPushButtons
|
||||
|
||||
@@ -1516,6 +1516,18 @@ QPushButton:checked {
|
||||
border-color: #819c0c;
|
||||
}
|
||||
|
||||
/*==================================================================================================
|
||||
Tool button Icon fix in save dialogs
|
||||
==================================================================================================*/
|
||||
/* found under Tools -> Save Picture */ /* Draft -> ShapeString -> Font file */
|
||||
|
||||
QFileDialog#QFileDialog QToolButton {
|
||||
background-color: transparent;
|
||||
padding: 1px;
|
||||
border: 1px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
|
||||
/*==================================================================================================
|
||||
Tool button inside QDialogs that works as QPushButtons
|
||||
|
||||
@@ -1516,6 +1516,18 @@ QPushButton:checked {
|
||||
border-color: #d0970c;
|
||||
}
|
||||
|
||||
/*==================================================================================================
|
||||
Tool button Icon fix in save dialogs
|
||||
==================================================================================================*/
|
||||
/* found under Tools -> Save Picture */ /* Draft -> ShapeString -> Font file */
|
||||
|
||||
QFileDialog#QFileDialog QToolButton {
|
||||
background-color: transparent;
|
||||
padding: 1px;
|
||||
border: 1px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
|
||||
/*==================================================================================================
|
||||
Tool button inside QDialogs that works as QPushButtons
|
||||
|
||||
+329
-130
@@ -24,7 +24,9 @@ INSTALLATION
|
||||
WINDOWS = C:/[INSTALLATION_PATH]/FreeCAD/data/Gui/Stylesheets/
|
||||
LINUX = /home/[YOUR_USER_NAME]/.FreeCAD/Gui/Stylesheets/
|
||||
|
||||
============================================================================================================
|
||||
============================================================================================================
|
||||
THESE COLOURS WERE USED AS TEMP SCRATCHPAD FOR DESIGNING. PLEASE DISREGARD!
|
||||
|
||||
BACKGROUND (darker to lighter)
|
||||
black
|
||||
#1e1e1e
|
||||
@@ -74,10 +76,23 @@ QToolBar * {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
/*==================================================================================================
|
||||
Style Links
|
||||
==================================================================================================*/
|
||||
QLabel[haslink="true"] {
|
||||
color: #55aaff;
|
||||
}
|
||||
|
||||
Gui--UrlLabel {
|
||||
color: #55aaff;
|
||||
}
|
||||
|
||||
/*==================================================================================================
|
||||
Main window
|
||||
==================================================================================================*/
|
||||
QWidget {
|
||||
background-color: #333333;
|
||||
}
|
||||
QMainWindow,
|
||||
QDialog,
|
||||
QDockWidget,
|
||||
@@ -130,6 +145,10 @@ QToolBox::tab:hover
|
||||
/*==================================================================================================
|
||||
QStatusBar
|
||||
==================================================================================================*/
|
||||
QStatusBar > QLabel {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
|
||||
QStatusBar::item {
|
||||
border: 1px solid #333333;
|
||||
@@ -207,7 +226,7 @@ QMenu QToolButton:pressed,
|
||||
QMenu QPushButton:selected,
|
||||
QMenu QToolButton:selected {
|
||||
color: white;
|
||||
background-color: #696969; /* same as QMenu::item:selected and QMenu::item:pressed */
|
||||
background-color: #557bb6; /* same as QMenu::item:selected and QMenu::item:pressed */
|
||||
}
|
||||
|
||||
QMenu QRadioButton:disabled,
|
||||
@@ -271,9 +290,9 @@ QToolBar::separator:vertical {
|
||||
Group box
|
||||
==================================================================================================*/
|
||||
QGroupBox {
|
||||
color: rgba(255,255,255,120);
|
||||
color: #bcbcbc;
|
||||
border:1px solid rgba(255,255,255,20); /* lighter than its own border-color */;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
margin-top: 10px;
|
||||
padding: 6px;
|
||||
background-color: rgba(255,255,255,0);
|
||||
@@ -300,10 +319,10 @@ Tooltip
|
||||
==================================================================================================*/
|
||||
QToolTip {
|
||||
color: #ffffff;
|
||||
background-color: #1e1e1e;
|
||||
background-color: #2a2a2a;
|
||||
/*opacity: 90%; doesn't correctly work */
|
||||
padding: 4px;
|
||||
border-radius: 2px; /* has no effect */
|
||||
border-radius: 1px; /* has no effect */
|
||||
}
|
||||
|
||||
|
||||
@@ -319,17 +338,17 @@ QDockWidget {
|
||||
|
||||
QDockWidget::title {
|
||||
text-align: center;
|
||||
background-color: rgba(0,0,0,40);
|
||||
border: 4px solid #333333; /* fix to simulate margin between this :title and tabs */ /* same as main background color */
|
||||
border-radius: 6px; /* bigger than normal due to previous border fix */
|
||||
padding: 4px 0px; /* also needed because of previous border fix */
|
||||
background-color: #2a2a2a;
|
||||
border-bottom: 4px solid #333333; /* fix to simulate margin between this :title and tabs */ /* same as main background color */
|
||||
margin-left: 6px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
QDockWidget::close-button,
|
||||
QDockWidget::float-button {
|
||||
border: none;
|
||||
background: transparent;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
subcontrol-origin: padding;
|
||||
subcontrol-position: right center;
|
||||
}
|
||||
@@ -344,18 +363,18 @@ QDockWidget::float-button {
|
||||
|
||||
QDockWidget::close-button:hover,
|
||||
QDockWidget::float-button:hover {
|
||||
background-color: rgba(0,0,0,60);
|
||||
background-color: #557bb6;
|
||||
}
|
||||
|
||||
QDockWidget::close-button:pressed,
|
||||
QDockWidget::float-button:pressed {
|
||||
background-color: rgba(0,0,0,120);
|
||||
background-color: #42608d;
|
||||
border: 2px solid #76acfd
|
||||
}
|
||||
|
||||
/* fix for Python Console (probably there is a smarter way to arrive to it) */
|
||||
QDockWidget > QFrame {
|
||||
background-color: #3C3C3C;
|
||||
|
||||
background-color: #3c3c3c;
|
||||
border: 6px solid #333333;
|
||||
}
|
||||
|
||||
@@ -366,16 +385,17 @@ Progress bar
|
||||
QProgressBar,
|
||||
QProgressBar:horizontal {
|
||||
color: white;
|
||||
min-height: 24px;
|
||||
background-color: rgba(0,0,0,70);
|
||||
text-align: center;
|
||||
border: 1px solid rgba(0,0,0,140);
|
||||
padding: 1px;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
}
|
||||
QProgressBar::chunk,
|
||||
QProgressBar::chunk:horizontal {
|
||||
background-color: qlineargradient(spread:pad, x1:1, y1:0.545, x2:1, y2:0, stop:0 #3874f2, stop:1 #557BB6);
|
||||
border-radius: 2px;
|
||||
background-color: #557BB6;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
|
||||
@@ -383,7 +403,7 @@ QProgressBar::chunk:horizontal {
|
||||
Scroll
|
||||
==================================================================================================*/
|
||||
QAbstractScrollArea {
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
@@ -410,7 +430,7 @@ QScrollBar::handle:horizontal:hover {
|
||||
|
||||
QScrollBar::handle:horizontal {
|
||||
min-width: 5px;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
margin: 4px 15px;
|
||||
}
|
||||
|
||||
@@ -435,11 +455,13 @@ QScrollBar::add-line:horizontal {
|
||||
QScrollBar::sub-line:horizontal:hover,
|
||||
QScrollBar::sub-line:horizontal:on {
|
||||
border-image: url(qss:images_dark-light/left_arrow_lighter.svg);
|
||||
background-color: #557BB6;
|
||||
}
|
||||
|
||||
QScrollBar::add-line:horizontal:hover,
|
||||
QScrollBar::add-line:horizontal:on {
|
||||
border-image: url(qss:images_dark-light/right_arrow_lighter.svg);
|
||||
background-color: #557BB6;
|
||||
}
|
||||
|
||||
QScrollBar::up-arrow:horizontal,
|
||||
@@ -460,7 +482,7 @@ QScrollBar:vertical {
|
||||
|
||||
QScrollBar::handle:vertical {
|
||||
min-height: 24px;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
margin: 15px 4px;
|
||||
}
|
||||
|
||||
@@ -485,11 +507,13 @@ QScrollBar::add-line:vertical {
|
||||
QScrollBar::sub-line:vertical:hover,
|
||||
QScrollBar::sub-line:vertical:on {
|
||||
border-image: url(qss:images_dark-light/up_arrow_lighter.svg);
|
||||
background-color: #557BB6;
|
||||
}
|
||||
|
||||
QScrollBar::add-line:vertical:hover,
|
||||
QScrollBar::add-line:vertical:on {
|
||||
border-image: url(qss:images_dark-light/down_arrow_lighter.svg);
|
||||
background-color: #557BB6;
|
||||
}
|
||||
|
||||
QScrollBar::up-arrow:vertical,
|
||||
@@ -507,7 +531,7 @@ QScrollBar::sub-page:vertical {
|
||||
Tab bar
|
||||
==================================================================================================*/
|
||||
QTabWidget::pane {
|
||||
background-color: #333333; /* temporal (transparent background) */ /* tab content background color */ /* was transparent. fixes no color undocked Combo View */
|
||||
background-color: transparent; /* temporal (transparent background) */ /* tab content background color */ /* was transparent. fixes no color undocked Combo View */
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
@@ -543,7 +567,7 @@ QTabWidget::tab-bar:right {
|
||||
|
||||
QTabBar {
|
||||
qproperty-drawBase: 0; /* important */
|
||||
background-color: #333333; /* Hack for Undocked white background - was transparent*/
|
||||
background-color: transparent; /* Hack for Undocked white background - was transparent*/
|
||||
}
|
||||
|
||||
/* Workaround for QTabBars created from docked QDockWidgets which don't draw the border if not set and reset as follows: */
|
||||
@@ -642,12 +666,13 @@ QDialog#Gui__Dialog__DlgPreferences QTabWidget::pane {
|
||||
|
||||
/* hack to correctly align Preferences icon list on OSX */
|
||||
QDialog#Gui__Dialog__DlgPreferences > QListView {
|
||||
min-width: 130px;
|
||||
min-width: 108px; /* narrowed for new smaller icons - was 130px*/
|
||||
max-width: 108px;
|
||||
}
|
||||
|
||||
/* unique styles for sections inside Preferences */
|
||||
QDialog#Gui__Dialog__DlgPreferences > QListView::item {
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
QDialog#Gui__Dialog__DlgPreferences > QListView::item:hover { /* Preference left icons*/
|
||||
@@ -667,7 +692,7 @@ Tab bar buttons
|
||||
QTabBar::close-button {
|
||||
subcontrol-origin: margin;
|
||||
subcontrol-position: center right; /* only works for Qt 4.6 and newer */;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
background-image: url(qss:images_dark-light/close_light.svg);
|
||||
background-position: center center;
|
||||
background-repeat: none;
|
||||
@@ -770,7 +795,7 @@ QTableView {
|
||||
selection-color: #ffffff;
|
||||
selection-background-color: #557BB6; /* should be similar to QListView::item selected background-color */
|
||||
show-decoration-selected: 1; /* make the selection span the entire width of the view */
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
QListView::item:hover,
|
||||
@@ -801,7 +826,7 @@ Gui--PropertyEditor--PropertyEditor > QWidget > QWidget > QLabel:disabled {
|
||||
color: transparent;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
@@ -820,8 +845,8 @@ Gui--PropertyEditor--PropertyEditor QAbstractSpinBox:disabled {
|
||||
|
||||
/* hack to hide weird redundant information inside cells with links and no editable data (but editable via "..." button) */
|
||||
Gui--PropertyEditor--PropertyEditor > QWidget > QWidget > QLabel {
|
||||
color: #557BB6;
|
||||
background-color: #696969; /* same as focused background color */
|
||||
color: #949494;
|
||||
background-color: #2a2a2a; /* same as focused background color */
|
||||
}
|
||||
|
||||
/* hack to disable margin inside Property values to following elements */
|
||||
@@ -874,7 +899,7 @@ QTreeView > QWidget > QTimeEdit:down-button,
|
||||
QTreeView > QWidget > QDateEdit:down-button,
|
||||
QTreeView > QWidget > QDateTimeEdit:down-button,
|
||||
QTreeView > QWidget > Gui--ColorButton {
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
/* set focus colors to best viewing the editable fields */
|
||||
@@ -907,7 +932,7 @@ QTreeView > QWidget > QDateTimeEdit:read-only {
|
||||
/* Fix to correctly (not totally) draw QTextEdit on OSX at Page properties: "Page result", "Template" and "Editable Texts" */
|
||||
Gui--PropertyEditor--PropertyEditor > QWidget > QWidget > QWidget {
|
||||
min-height: 14px;
|
||||
border-radius: 2px; /* reset */
|
||||
border-radius: 1px; /* reset */
|
||||
}
|
||||
|
||||
|
||||
@@ -917,8 +942,8 @@ Header of tree and list views
|
||||
QHeaderView {
|
||||
color: #d2d2d2;
|
||||
background-color: #2a2a2a;
|
||||
border-top-left-radius: 2px; /* 1px less than its container */
|
||||
border-top-right-radius: 2px; /* 1px less than its container */
|
||||
border-top-left-radius: 1px; /* 1px less than its container */
|
||||
border-top-right-radius: 1px; /* 1px less than its container */
|
||||
border-bottom-left-radius: 0px;
|
||||
border-bottom-right-radius: 0px;
|
||||
}
|
||||
@@ -1057,7 +1082,7 @@ Text/Python editor (macros, etc...)
|
||||
==================================================================================================*/
|
||||
QPlainTextEdit,
|
||||
QPlainTextEdit:focus {
|
||||
background-color: #3C3C3C; /* Python Console */
|
||||
background-color: #3c3c3c; /* Python Console */
|
||||
selection-color: #f5f5f5;
|
||||
selection-background-color: #557BB6;
|
||||
border: 6px solid #333333;
|
||||
@@ -1181,12 +1206,12 @@ QSint--ActionGroup QFrame[class="content"] > QWidget > QPushButton {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
/* Fix for lists inside task panels */
|
||||
/* Fix for lists inside task panels */ /* sketcher constraints list */
|
||||
QSint--ActionGroup QFrame[class="content"] QTreeView,
|
||||
QSint--ActionGroup QFrame[class="content"] QListView,
|
||||
QSint--ActionGroup QFrame[class="content"] QTableView {
|
||||
color: #f5f5f5;
|
||||
background-color: #3C3C3C;
|
||||
background-color: #494949;
|
||||
}
|
||||
|
||||
|
||||
@@ -1194,6 +1219,24 @@ QSint--ActionGroup QFrame[class="content"] QTableView {
|
||||
Buttons
|
||||
==================================================================================================*/
|
||||
/* Common */
|
||||
QToolBar > Gui--WorkbenchComboBox {
|
||||
color: #f5f5f5;
|
||||
background-color: #2a2a2a; /* workbench picker and drop-down */
|
||||
selection-color: #ffffff;
|
||||
selection-background-color: #2a2a2a;
|
||||
border: 1px solid #2a2a2a;
|
||||
border-radius: 1px;
|
||||
min-width: 50px; /* it ensures the default value is correctly displayed */
|
||||
min-height: 16px; /* important to be a pair number in order to up/down buttons to be divisible by two (if not set could create a blank line in Ubuntu. Its downside is that it's needed to reset it (min-width: 0px) on following elements that can't have it such as fields inside QToolBar and inside QTreeView (Property editor) */
|
||||
padding: 1px 2px; /* temporal: could don't be compatible with elements inside Tree/List view */
|
||||
}
|
||||
|
||||
QToolBar > Gui--WorkbenchComboBox:!editable {
|
||||
color: #f5f5f5;
|
||||
font-weight: bold;
|
||||
background-color: #557bb6; /* workbench disabled color */
|
||||
}
|
||||
|
||||
QComboBox,
|
||||
QAbstractSpinBox,
|
||||
QSpinBox,
|
||||
@@ -1204,13 +1247,13 @@ QTimeEdit,
|
||||
QDateEdit,
|
||||
QDateTimeEdit {
|
||||
color: #f5f5f5;
|
||||
background-color: #696969;
|
||||
background-color: #494949; /* lineedits and drop-downs */
|
||||
selection-color: #ffffff;
|
||||
selection-background-color: #557BB6;
|
||||
selection-background-color: #557bb6;
|
||||
border: 0px solid #2a2a2a;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
min-width: 50px; /* it ensures the default value is correctly displayed */
|
||||
min-height: 20px; /* important to be a pair number in order to up/down buttons to be divisible by two (if not set could create a blank line in Ubuntu. Its downside is that it's needed to reset it (min-width: 0px) on following elements that can't have it such as fields inside QToolBar and inside QTreeView (Property editor) */
|
||||
min-height: 16px; /* important to be a pair number in order to up/down buttons to be divisible by two (if not set could create a blank line in Ubuntu. Its downside is that it's needed to reset it (min-width: 0px) on following elements that can't have it such as fields inside QToolBar and inside QTreeView (Property editor) */
|
||||
padding: 1px 2px; /* temporal: could don't be compatible with elements inside Tree/List view */
|
||||
}
|
||||
|
||||
@@ -1234,7 +1277,7 @@ QDateTimeEdit {
|
||||
QTextEdit:!editable,
|
||||
QTextEdit:!editable:focus {
|
||||
color: #f5f5f5;
|
||||
background-color: #3C3C3C;
|
||||
background-color: #3c3c3c;
|
||||
border: 6px solid #333333;
|
||||
border-radius: 0px;
|
||||
margin: 0px;
|
||||
@@ -1252,10 +1295,10 @@ QDateEdit:focus,
|
||||
QDateTimeEdit:focus {
|
||||
font-weight: bold;
|
||||
color: #f5f5f5;
|
||||
border-color: #3c3c3c;
|
||||
border-color: #333333;
|
||||
border: 1px;
|
||||
border-right-color: #557BB6; /* same as up/down or drop-down button color */
|
||||
background-color: #696969;
|
||||
background-color: #494949;
|
||||
}
|
||||
|
||||
QComboBox:disabled,
|
||||
@@ -1267,8 +1310,8 @@ QTextEdit:disabled,
|
||||
QTimeEdit:disabled,
|
||||
QDateEdit:disabled,
|
||||
QDateTimeEdit:disabled {
|
||||
color: #f5f5f5;
|
||||
background-color: #696969; /* same as enabled color */
|
||||
color: #696969;
|
||||
background-color: #494949; /* same as enabled color */
|
||||
border-color: #2a2a2a; /* same as enabled color */
|
||||
}
|
||||
|
||||
@@ -1315,7 +1358,7 @@ QDoubleSpinBox:up-button:focus,
|
||||
QTimeEdit:up-button:focus,
|
||||
QDateEdit:up-button:focus,
|
||||
QDateTimeEdit:up-button:focus {
|
||||
background-color: #557BB6;
|
||||
background-color: #2a2a2a;
|
||||
}
|
||||
|
||||
QAbstractSpinBox:down-button:focus,
|
||||
@@ -1324,7 +1367,7 @@ QDoubleSpinBox:down-button:focus,
|
||||
QTimeEdit:down-button:focus,
|
||||
QDateEdit:down-button:focus,
|
||||
QDateTimeEdit:down-button:focus {
|
||||
background-color: #557BB6;
|
||||
background-color: #2a2a2a;
|
||||
}
|
||||
|
||||
QAbstractSpinBox:up-button:disabled,
|
||||
@@ -1423,13 +1466,13 @@ QComboBox::drop-down {
|
||||
subcontrol-origin: border; /* important */
|
||||
subcontrol-position: top right;
|
||||
width: 20px;
|
||||
border-top-right-radius: 2px;
|
||||
border-bottom-right-radius: 2px;
|
||||
border-top-right-radius: 1px;
|
||||
border-bottom-right-radius: 1px;
|
||||
}
|
||||
|
||||
QComboBox::drop-down:on,
|
||||
QComboBox::drop-down:focus {
|
||||
background-color: #557BB6;
|
||||
background-color: #2a2a2a;
|
||||
}
|
||||
|
||||
QComboBox::down-arrow {
|
||||
@@ -1454,7 +1497,7 @@ QComboBox {
|
||||
|
||||
QComboBox QAbstractItemView {
|
||||
color: #bebebe; /* same as regular QComboBox color */
|
||||
background-color: #2a2a2a; /* was transparent */
|
||||
background-color: transparent; /* was transparent */
|
||||
selection-color: #f5f5f5;
|
||||
selection-background-color: #557BB6;
|
||||
border-width: 5px 0px 5px 0px;
|
||||
@@ -1470,38 +1513,153 @@ Push button
|
||||
QPushButton {
|
||||
color: #e0e0e0;
|
||||
text-align: center;
|
||||
background-color: qlineargradient(spread:pad, x1:0, y1:0.3, x2:0, y2:1, stop:0 #696969, stop:1 #696961); /* Middle Mouse Navigation Button and Ok Cancel Apply Help Preferences Buttons */
|
||||
border: 2px;
|
||||
border-color: #2a2a2a;
|
||||
background-color: #2a2a2a;
|
||||
padding: 4px 20px;
|
||||
margin: 2px 2px;
|
||||
margin-right: 5px;
|
||||
min-height: 20px; /* same as QTabBar QPushButton min-width */
|
||||
border-radius: 2px;
|
||||
|
||||
border: 1px solid #494949;
|
||||
margin: 4px 4px;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
QPushButton:hover,
|
||||
QPushButton:focus {
|
||||
color: #cbd8e6;
|
||||
border-color: #2a2a2a;
|
||||
background-color: #557BB6;
|
||||
color: #ffffff;
|
||||
background-color: #557bb6;
|
||||
border: 1px solid #f5f5f5;
|
||||
}
|
||||
|
||||
QPushButton:disabled,
|
||||
QPushButton:disabled:checked {
|
||||
color: #2a2a2a;
|
||||
background-color: #696969; /* same as enabled color */
|
||||
border-color: #2a2a2a; /* same as enabled color */
|
||||
color: #f5f5f5;
|
||||
background-color: #2a2a2a; /* same as enabled color */
|
||||
border: 1px solid #2a2a2a; /* same as enabled color */
|
||||
}
|
||||
|
||||
QPushButton:pressed {
|
||||
background-color: #557BB6;
|
||||
color: #ffffff;
|
||||
background-color: #48699a;
|
||||
border: 1px solid #3c3c3c;
|
||||
}
|
||||
|
||||
QPushButton:checked {
|
||||
background-color: #696969;
|
||||
border-color: #557BB6;
|
||||
background-color: #557BB6;
|
||||
border: 1px solid #557BB6;
|
||||
}
|
||||
|
||||
/* Inspect Widgets Addon */
|
||||
|
||||
QDockWidget#InspectWidgets QPushButton {
|
||||
background-color: #2a2a2a;
|
||||
border: 1px solid #3c3c3c;
|
||||
min-height: 16px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
QDockWidget#InspectWidgets QPushButton:hover {
|
||||
color: #ffffff;
|
||||
background-color: #557bb6;
|
||||
border: 1px solid #f5f5f5;
|
||||
border-bottom: 1px solid #f5f5f5;
|
||||
}
|
||||
|
||||
QDockWidget#InspectWidgets QPushButton:checked,
|
||||
QDockWidget#InspectWidgets QPushButton:pressed {
|
||||
background-color: #557bb6;
|
||||
border: 1px solid #557bb6;
|
||||
}
|
||||
|
||||
/* CAD Navigation Style */
|
||||
|
||||
QPushButton#NavigationIndicator {
|
||||
background-color: #557bb6;
|
||||
padding: 2px;
|
||||
margin: 0px;
|
||||
border: 1px solid #333333;
|
||||
border-radius: 1px;
|
||||
min-width: 90px;
|
||||
min-height: 24px;
|
||||
}
|
||||
|
||||
QPushButton:hover#NavigationIndicator {
|
||||
color: #ffffff;
|
||||
border: 1px solid #f5f5f5;
|
||||
}
|
||||
|
||||
QPushButton:pressed#NavigationIndicator {
|
||||
color: #ffffff;
|
||||
background-color: #557bb6;
|
||||
border: 1px solid #557bb6;
|
||||
}
|
||||
|
||||
/* BIM Views Manager */
|
||||
|
||||
QWidget#Form QPushButton {
|
||||
background-color: #333333;
|
||||
padding: 4px 2px;
|
||||
border: 1px solid #3c3c3c;
|
||||
border-radius: 1px;
|
||||
margin: 2px;
|
||||
margin-bottom: 8px;
|
||||
max-width: 100%;
|
||||
min-width: 16px;
|
||||
min-height: 24px;
|
||||
}
|
||||
|
||||
QWidget#Form QPushButton:hover {
|
||||
border: 1px solid #f5f5f5;
|
||||
background-color: #557BB6;
|
||||
}
|
||||
|
||||
QWidget#Form QPushButton:pressed {
|
||||
border: 1px solid #557bb6;
|
||||
background-color: #557BB6;
|
||||
}
|
||||
|
||||
/* Sketcher Manual Update Button */
|
||||
|
||||
QPushButton#manualUpdate {
|
||||
padding: 4px;
|
||||
margin: 0px;
|
||||
border: 1px solid #494949;
|
||||
}
|
||||
|
||||
QPushButton:pressed#manualUpdate {
|
||||
color: #ffffff;
|
||||
border: 1px solid #3c3c3c;
|
||||
background-color: #48699a;
|
||||
}
|
||||
|
||||
/* Addon Manager */
|
||||
|
||||
QDialog#Dialog QPushButton {
|
||||
padding: 4px;
|
||||
margin: 0px;
|
||||
border: 1px solid #494949;
|
||||
}
|
||||
|
||||
QDialog#Dialog QPushButton:hover {
|
||||
color: #ffffff;
|
||||
border: 1px solid #3c3c3c;
|
||||
background-color: #48699a;
|
||||
}
|
||||
|
||||
QPushButton#buttonUninstall {
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
QPushButton#buttonClose {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
/* Ok Cancel Apply Help Preferences Buttons */ /* Hack to move Help button left */
|
||||
|
||||
QDialogButtonBox > QPushButton {
|
||||
color: #e0e0e0;
|
||||
text-align: center;
|
||||
background-color: #2a2a2a;
|
||||
border: 1px solid #494949;
|
||||
padding: 4px;
|
||||
margin-right: 8px;
|
||||
min-width: 60px;
|
||||
}
|
||||
|
||||
/* Color Buttons */
|
||||
@@ -1538,7 +1696,7 @@ Gui--PropertyEditor--PropertyEditor > QWidget > QWidget > QPushButton {
|
||||
background-color: #2a2a2a;
|
||||
border: 1px solid #1e1e1e;
|
||||
min-width: 16px; /* reset it due to larger value on regular QPushButton, same or bigger value as regular QPushButton min-height */
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
margin: 0px; /* reset */
|
||||
padding: 0px; /* reset */
|
||||
}
|
||||
@@ -1547,48 +1705,63 @@ Gui--PropertyEditor--PropertyEditor > QWidget > QWidget > QPushButton {
|
||||
Gui--PropertyEditor--PropertyEditor > QWidget > QWidget > QWidget > QWidget > QFrame {
|
||||
background-color: #333333; /* main background color */
|
||||
border: 1px solid #333333;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
padding: 2px 6px;
|
||||
}
|
||||
|
||||
QPushButton:checked {
|
||||
background-color: #696969;
|
||||
border-color: #696969;
|
||||
/*==================================================================================================
|
||||
Tool button Icon fix in save dialogs
|
||||
==================================================================================================*/
|
||||
/* found under Tools -> Save Picture */ /* Draft -> ShapeString -> Font file */
|
||||
|
||||
QFileDialog#QFileDialog QToolButton {
|
||||
background-color: transparent;
|
||||
padding: 1px;
|
||||
border: 1px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
QFileDialog#QFileDialog QToolButton:hover,
|
||||
QFileDialog#QFileDialog QToolButton:focus {
|
||||
color: #ffffff;
|
||||
background-color: #557bb6;
|
||||
border: 1px solid #f5f5f5;
|
||||
}
|
||||
|
||||
/*==================================================================================================
|
||||
Tool button inside QDialogs that works as QPushButtons
|
||||
==================================================================================================*/
|
||||
/* found under Tools -> Customize -> Macros -> Pixmap "..." button */
|
||||
|
||||
QDialog QToolButton {
|
||||
color: #e0e0e0;
|
||||
text-align: center;
|
||||
background-color: qlineargradient(spread:pad, x1:0, y1:0.3, x2:0, y2:1, stop:0 #2a2a2a, stop:1 #1e1e1e);
|
||||
border: 1px solid #1e1e1e;
|
||||
border-bottom-color: black; /* simulates shadow under the button */
|
||||
background-color: #2a2a2a;
|
||||
border: 1px solid #494949;
|
||||
padding: 0px; /* different than regular QPushButton */
|
||||
margin: 2px; /* different than regular QPushButton */
|
||||
margin: 2px;
|
||||
min-height: 16px; /* same as QTabBar QPushButton min-width */
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
QDialog QToolButton:hover,
|
||||
QDialog QToolButton:focus {
|
||||
color: #cbd8e6;
|
||||
border-color: #557BB6;
|
||||
background-color: #557BB6;
|
||||
color: #ffffff;
|
||||
background-color: #557bb6;
|
||||
border: 1px solid #f5f5f5;
|
||||
}
|
||||
|
||||
QDialog QToolButton:disabled,
|
||||
QDialog QToolButton:disabled:checked {
|
||||
color: #333333;
|
||||
border-color: #424242;
|
||||
background-color: #424242;
|
||||
color: #f5f5f5;
|
||||
background-color: #2a2a2a;
|
||||
border: 1px solid #2a2a2a;
|
||||
}
|
||||
|
||||
QDialog QToolButton:pressed {
|
||||
background-color: #557BB6;
|
||||
color: #ffffff;
|
||||
background-color: #48699a;
|
||||
border: 1px solid #3c3c3c;
|
||||
}
|
||||
|
||||
|
||||
@@ -1599,26 +1772,26 @@ Tool button inside Task Panel content that works as QPushButtons
|
||||
QSint--ActionGroup QFrame[class="content"] QToolButton {
|
||||
color: #e0e0e0;
|
||||
text-align: center;
|
||||
background-color: qlineargradient(spread:pad, x1:0, y1:0.3, x2:0, y2:1, stop:0 #2a2a2a, stop:1 #1e1e1e);
|
||||
border: 1px solid #1e1e1e;
|
||||
background-color: #2a2a2a;
|
||||
border: 1px solid #494949;
|
||||
border-bottom-color: black; /* simulates shadow under the button */
|
||||
padding: 2px 6px; /* different than regular QPushButton */
|
||||
margin: 2px; /* different than regular QPushButton */
|
||||
min-height: 16px; /* same as QTabBar QPushButton min-width */
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
QSint--ActionGroup QFrame[class="content"] QToolButton:hover,
|
||||
QSint--ActionGroup QFrame[class="content"] QToolButton:focus {
|
||||
color: white;
|
||||
border-color: #557BB6;
|
||||
border-color: solid #f5f5f5;
|
||||
background-color: #557BB6;
|
||||
}
|
||||
|
||||
QSint--ActionGroup QFrame[class="content"] QToolButton:disabled,
|
||||
QSint--ActionGroup QFrame[class="content"] QToolButton:disabled:checked {
|
||||
color: #333333;
|
||||
border-color: #424242;
|
||||
color: #f5f5f5;
|
||||
border-color: #494949;
|
||||
background-color: #424242;
|
||||
}
|
||||
|
||||
@@ -1639,7 +1812,7 @@ QSint--ActionGroup QFrame[class="content"] QMenu::item {
|
||||
}
|
||||
|
||||
QSint--ActionGroup QFrame[class="content"] QComboBox QAbstractItemView {
|
||||
background-color: #696969;
|
||||
background-color: #333333;
|
||||
}
|
||||
|
||||
|
||||
@@ -1673,7 +1846,7 @@ QRadioButton:disabled {
|
||||
QRadioButton::indicator {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
QRadioButton::indicator:pressed {
|
||||
@@ -1838,7 +2011,7 @@ QSlider:vertical {
|
||||
QSlider::groove {
|
||||
background-color: #2a2a2a;
|
||||
border: 2px solid #3c3c3c;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
margin: 4px 0px;
|
||||
}
|
||||
|
||||
@@ -1862,7 +2035,7 @@ QSlider::handle:vertical {
|
||||
border: 1px solid #2a2a2a;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
QSlider::handle:horizontal {
|
||||
@@ -1918,39 +2091,48 @@ QToolBar > QDateTimeEdit {
|
||||
}
|
||||
|
||||
QToolBar > QPushButton {
|
||||
padding: 4px;
|
||||
padding: 2px;
|
||||
margin: 0px; /* doesn't work with :left, :right:, :top or :bottom sub-controls */
|
||||
min-width: 24px; /* could not be larger due to switchable Preferences "Size of toolbar icons" */
|
||||
min-height: 20px; /* could not be larger due to switchable Preferences "Size of toolbar icons" */
|
||||
border-radius: 2px; /* same as regular QPushButton */
|
||||
min-height: 24px; /* could not be larger due to switchable Preferences "Size of toolbar icons" */
|
||||
border-radius: 1px; /* same as regular QPushButton */
|
||||
}
|
||||
|
||||
QToolBar > QPushButton:checked {
|
||||
border: 1px solid #333333;
|
||||
border: 1px solid #3c3c3c;
|
||||
background-color: #557BB6;
|
||||
}
|
||||
|
||||
/* Hack to avoid QPushButton text partially hidden under menu-indicator */
|
||||
QToolBar > QPushButton::menu-indicator:!checked {
|
||||
image: none;
|
||||
width: 0px;
|
||||
}
|
||||
|
||||
QToolBar > QPushButton:!checked {
|
||||
background-color: #333333; /* Current Working Plane and Nudge */
|
||||
border: 1px solid #333333;
|
||||
text-align: left;
|
||||
padding: 2px 4px;
|
||||
border: 1px solid #3c3c3c;
|
||||
margin: 0px 2px;
|
||||
}
|
||||
|
||||
QToolBar > QPushButton:checked:hover {
|
||||
border-color: #557BB6;
|
||||
border: 1px solid #f5f5f5;
|
||||
}
|
||||
|
||||
QToolBar > QPushButton:!checked:hover {
|
||||
color: #ffffff;
|
||||
background-color: #557BB6;
|
||||
border-color: #557BB6;
|
||||
border: 1px solid #f5f5f5;
|
||||
}
|
||||
|
||||
QToolBar > QPushButton:checked:pressed {
|
||||
border: 1px solid #557bb6;
|
||||
background-color: solid #557BB6;
|
||||
}
|
||||
|
||||
QToolBar > QPushButton:!checked:pressed {
|
||||
border: 1px solid #557bb6;
|
||||
background-color: #557BB6;
|
||||
}
|
||||
|
||||
@@ -1963,43 +2145,60 @@ QToolBar > QPushButton:!checked:disabled {
|
||||
QToolBar > QToolButton {
|
||||
margin: 2px;
|
||||
padding: 2px;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
QToolBar > QToolButton:hover {
|
||||
background-color: #557BB6;
|
||||
border: 1px solid #f5f5f5;
|
||||
}
|
||||
|
||||
QToolBar > QToolButton:pressed {
|
||||
background-color: #557BB6;
|
||||
border: 1px solid #557bb6;
|
||||
}
|
||||
|
||||
/* ToolBar menu buttons (buttons with drop-down menu) */
|
||||
QToolBar > QToolButton#qt_toolbutton_menubutton {
|
||||
padding-right: 20px; /* Hack to add more width to buttons with menu */
|
||||
border: 1px solid transparent;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
QToolBar > QToolButton#qt_toolbutton_menubutton:hover,
|
||||
QToolBar > QToolButton#qt_toolbutton_menubutton:pressed,
|
||||
QToolBar > QToolButton#qt_toolbutton_menubutton:open {
|
||||
border: 1px solid #557BB6;
|
||||
border: 1px solid #333333;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
QToolBar QToolButton::menu-button,
|
||||
QToolBar > QToolButton#qt_toolbutton_menubutton::menu-button {
|
||||
border: none;
|
||||
border-top-right-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
border-top-right-radius: 1px;
|
||||
border-bottom-right-radius: 1px;
|
||||
width: 16px; /* 16px width + 4px for border = 20px allocated above */
|
||||
outline: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
QToolBar > QToolButton#qt_toolbutton_menubutton::menu-button:hover,
|
||||
QToolBar > QToolButton#qt_toolbutton_menubutton::menu-button:hover {
|
||||
border-top: 1px solid #f5f5f5;
|
||||
border-bottom: 1px solid #f5f5f5;
|
||||
border-right: 1px solid #f5f5f5;
|
||||
background-color: #557BB6;
|
||||
}
|
||||
|
||||
QToolBar > QToolButton#qt_toolbutton_menubutton:pressed,
|
||||
QToolBar > QToolButton#qt_toolbutton_menubutton:open {
|
||||
background-color: #557BB6;
|
||||
border: 1px solid #557BB6;
|
||||
}
|
||||
|
||||
QToolBar > QToolButton#qt_toolbutton_menubutton:hover {
|
||||
background-color: #557BB6;
|
||||
border: 1px solid #f5f5f5;
|
||||
}
|
||||
|
||||
QToolBar > QToolButton#qt_toolbutton_menubutton::menu-button:pressed,
|
||||
QToolBar > QToolButton#qt_toolbutton_menubutton::menu-button:open {
|
||||
border-top: 1px solid #557bb6;
|
||||
border-bottom: 1px solid #557bb6;
|
||||
border-right: 1px solid #557bb6;
|
||||
background-color: #557BB6;
|
||||
}
|
||||
|
||||
@@ -2058,14 +2257,14 @@ QToolBar QToolButton#qt_toolbar_ext_button:on {
|
||||
Tables (spreadsheets)
|
||||
==================================================================================================*/
|
||||
QTableView {
|
||||
gridline-color: #696969;
|
||||
gridline-color: #a8a8a8;
|
||||
selection-color: #ffffff;
|
||||
selection-background-color: #2D5C9A; /* Default Spreadsheet cell selection background color */
|
||||
background-color: #a0a0a0; /* Default Spreadsheet cell background color */
|
||||
selection-background-color: #557bb6; /* Default Spreadsheet cell selection background color */
|
||||
background-color: #cecece; /* Default Spreadsheet cell background color */
|
||||
}
|
||||
|
||||
QTableView::item:hover {
|
||||
background-color: rgba(0,0,0,10); /* temporal: is it displayed in Linux or Windows? on OSX it isn't */
|
||||
background-color: #557bb6; /* temporal: is it displayed in Linux or Windows? on OSX it isn't */
|
||||
}
|
||||
|
||||
QTableView::item:disabled {
|
||||
@@ -2074,7 +2273,7 @@ QTableView::item:disabled {
|
||||
|
||||
QTableView::item:selected {
|
||||
color: #a0a0a0;
|
||||
border-color: #cbd8e6; /* same as focused background color */
|
||||
border-color: #cecece; /* same as focused background color */
|
||||
border-bottom-color: #557BB6; /* same as focused border color */
|
||||
}
|
||||
|
||||
@@ -2102,7 +2301,7 @@ QTableView > QWidget > QTimeEdit:down-button,
|
||||
QTableView > QWidget > QDateEdit:down-button,
|
||||
QTableView > QWidget > QDateTimeEdit:down-button,
|
||||
QTableView > QWidget > Gui--ColorButton {
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
QTableView > QWidget > QComboBox,
|
||||
@@ -2114,7 +2313,7 @@ QTableView > QWidget > QTextEdit,
|
||||
QTableView > QWidget > QTimeEdit,
|
||||
QTableView > QWidget > QDateEdit,
|
||||
QTableView > QWidget > QDateTimeEdit {
|
||||
color: black;
|
||||
color: #f5f5f5;
|
||||
background-color: transparent;
|
||||
border-color: transparent;
|
||||
}
|
||||
@@ -2145,11 +2344,11 @@ QTableView > QWidget > QTextEdit:focus,
|
||||
QTableView > QWidget > QTimeEdit:focus,
|
||||
QTableView > QWidget > QDateEdit:focus,
|
||||
QTableView > QWidget > QDateTimeEdit:focus {
|
||||
color: #2a2a2a;
|
||||
selection-color: white;
|
||||
color: #000000;
|
||||
selection-color: #f5f5f5;
|
||||
selection-background-color: #557BB6;
|
||||
border-color: #cbd8e6;
|
||||
background-color: #cbd8e6;
|
||||
border-color: #3c3c3c;
|
||||
background-color: #cecece;
|
||||
}
|
||||
|
||||
QTableView > QWidget > QComboBox:disabled,
|
||||
@@ -2161,7 +2360,7 @@ QTableView > QWidget > QTextEdit:disabled,
|
||||
QTableView > QWidget > QTimeEdit:disabled,
|
||||
QTableView > QWidget > QDateEdit:disabled,
|
||||
QTableView > QWidget > QDateTimeEdit:disabled {
|
||||
color: rgba(0,0,0,120);
|
||||
color: #f5f5f5;
|
||||
background-color: transparent;
|
||||
border-color: transparent;
|
||||
}
|
||||
@@ -2175,7 +2374,7 @@ QTableView > QWidget > QTextEdit:read-only,
|
||||
QTableView > QWidget > QTimeEdit:read-only,
|
||||
QTableView > QWidget > QDateEdit:read-only,
|
||||
QTableView > QWidget > QDateTimeEdit:read-only {
|
||||
color: black;
|
||||
color: #f5f5f5;
|
||||
background-color: transparent;
|
||||
border-color: transparent;
|
||||
}
|
||||
@@ -2228,7 +2427,7 @@ QToolBar#Selector QToolButton {
|
||||
border: none;
|
||||
margin: 0px;
|
||||
padding: 2px 6px;
|
||||
border-radius: 2px;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
/* Active tab */
|
||||
|
||||
@@ -146,6 +146,10 @@ int main( int argc, char ** argv )
|
||||
#endif
|
||||
|
||||
#if defined (FC_OS_WIN32)
|
||||
// we need to force Coin not to use Freetype in order to find installed fonts on Windows
|
||||
// see https://forum.freecadweb.org/viewtopic.php?p=485142#p485016
|
||||
_putenv("COIN_FORCE_FREETYPE_OFF=1");
|
||||
|
||||
int argc_ = argc;
|
||||
QVector<QByteArray> data;
|
||||
QVector<char *> argv_;
|
||||
|
||||
@@ -248,26 +248,28 @@ def restart_freecad():
|
||||
QtCore.QProcess.startDetached(QtGui.QApplication.applicationFilePath(), args)
|
||||
|
||||
|
||||
def get_zip_url(baseurl):
|
||||
def get_zip_url(baseurl, branch="master"):
|
||||
"Returns the location of a zip file from a repo, if available"
|
||||
|
||||
url = getserver(baseurl).strip("/")
|
||||
if url.endswith("github.com"):
|
||||
return baseurl+"/archive/master.zip"
|
||||
elif url.endswith("framagit.org") or url.endswith("gitlab.com"):
|
||||
return baseurl+"/archive/" + branch + ".zip"
|
||||
elif url.endswith("framagit.org") or url.endswith("gitlab.com") or url.endswith("salsa.debian.org"):
|
||||
# https://framagit.org/freecad-france/mooc-workbench/-/archive/master/mooc-workbench-master.zip
|
||||
reponame = baseurl.strip("/").split("/")[-1]
|
||||
return baseurl+"/-/archive/master/"+reponame+"-master.zip"
|
||||
return baseurl+"/-/archive/" + branch + "/"+reponame+"-" + branch + ".zip"
|
||||
else:
|
||||
print("Debug: addonmanager_utilities.get_zip_url: Unknown git host:", url)
|
||||
return None
|
||||
|
||||
|
||||
def get_readme_url(url):
|
||||
def get_readme_url(url, branch="master"):
|
||||
"Returns the location of a readme file"
|
||||
|
||||
if "github" in url or "framagit" in url or "gitlab" in url:
|
||||
return url+"/raw/master/README.md"
|
||||
if "github" in url or "framagit" in url:
|
||||
return url+"/raw/" + branch + "/README.md"
|
||||
elif "gitlab" in url or "salsa.debian.org" in url:
|
||||
return url+"/-/raw/" + branch + "/README.md"
|
||||
else:
|
||||
print("Debug: addonmanager_utilities.get_readme_url: Unknown git host:", url)
|
||||
return None
|
||||
@@ -279,17 +281,17 @@ def get_desc_regex(url):
|
||||
|
||||
if "github" in url:
|
||||
return r'<meta property="og:description" content="(.*?)"'
|
||||
elif "framagit" in url or "gitlab" in url:
|
||||
elif "framagit" in url or "gitlab" in url or "salsa.debian.org" in url:
|
||||
return r'<meta.*?content="(.*?)".*?og:description.*?>'
|
||||
print("Debug: addonmanager_utilities.get_desc_regex: Unknown git host:", url)
|
||||
return None
|
||||
|
||||
|
||||
def get_readme_html_url(url):
|
||||
def get_readme_html_url(url, branch="master"):
|
||||
"""Returns the location of a html file containing readme"""
|
||||
|
||||
if "github" in url:
|
||||
return url + "/blob/master/README.md"
|
||||
return url + "/blob/" + branch + "/README.md"
|
||||
else:
|
||||
print("Debug: addonmanager_utilities.get_readme_html_url: Unknown git host:", url)
|
||||
return None
|
||||
|
||||
@@ -82,6 +82,8 @@ NOGIT = False # for debugging purposes, set this to True to always use http dow
|
||||
|
||||
NOMARKDOWN = False # for debugging purposes, set this to True to disable Markdown lib
|
||||
|
||||
url_to_branch_map = {} # Added to 0.19.3 to support branches with names other than "master"
|
||||
|
||||
"""Multithread workers for the Addon Manager"""
|
||||
|
||||
|
||||
@@ -137,12 +139,13 @@ class UpdateWorker(QtCore.QThread):
|
||||
u.close()
|
||||
p = re.findall((r'(?m)\[submodule\s*"(?P<name>.*)"\]\s*'
|
||||
r"path\s*=\s*(?P<path>.+)\s*"
|
||||
r"url\s*=\s*(?P<url>https?://.*)"), p)
|
||||
r"url\s*=\s*(?P<url>https?://.*)\s*"
|
||||
r"(branch\s*=\s*(?P<branch>.*)\s*)?"), p)
|
||||
basedir = FreeCAD.getUserAppDataDir()
|
||||
moddir = basedir + os.sep + "Mod"
|
||||
repos = []
|
||||
# querying official addons
|
||||
for name, path, url in p:
|
||||
for name, path, url, _, branch in p:
|
||||
self.info_label.emit(name)
|
||||
url = url.split(".git")[0]
|
||||
addondir = moddir + os.sep + name
|
||||
@@ -152,11 +155,20 @@ class UpdateWorker(QtCore.QThread):
|
||||
else:
|
||||
state = 0
|
||||
repos.append([name, url, state])
|
||||
if branch is None or len(branch) == 0:
|
||||
branch = "master"
|
||||
url_to_branch_map[url] = branch
|
||||
# querying custom addons
|
||||
customaddons = (FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Addons")
|
||||
.GetString("CustomRepositories", "").split("\n"))
|
||||
for url in customaddons:
|
||||
if url:
|
||||
if " " in url:
|
||||
addon_and_branch = addon.split(" ")
|
||||
url = addon_and_branch[0]
|
||||
branch = addon_and_branch[1]
|
||||
else:
|
||||
branch = "master"
|
||||
name = url.split("/")[-1]
|
||||
if name.lower().endswith(".git"):
|
||||
name = name[:-4]
|
||||
@@ -166,6 +178,7 @@ class UpdateWorker(QtCore.QThread):
|
||||
else:
|
||||
state = 1
|
||||
repos.append([name, url, state])
|
||||
url_to_branch_map[url] = branch
|
||||
if not repos:
|
||||
self.info_label.emit(translate("AddonsInstaller", "Unable to download addon list."))
|
||||
else:
|
||||
@@ -262,11 +275,15 @@ class CheckWBWorker(QtCore.QThread):
|
||||
except Exception:
|
||||
print("AddonManager: Unable to fetch git updates for repo", repo[0])
|
||||
else:
|
||||
if "git pull" in gitrepo.status():
|
||||
self.mark.emit(repo[0])
|
||||
upds.append(repo[0])
|
||||
# mark as already installed AND already checked for updates AND update available
|
||||
self.repos[self.repos.index(repo)][2] = 3
|
||||
try:
|
||||
if "git pull" in gitrepo.status():
|
||||
self.mark.emit(repo[0])
|
||||
upds.append(repo[0])
|
||||
# mark as already installed AND already checked for updates AND update available
|
||||
self.repos[self.repos.index(repo)][2] = 3
|
||||
except stderr:
|
||||
FreeCAD.Console.PrintWarning("AddonManager - " + repo[0] + " git status"
|
||||
" fatal: this operation must be run in a work tree \n")
|
||||
self.addon_repos.emit(self.repos)
|
||||
self.enable.emit(len(upds))
|
||||
self.stop = True
|
||||
@@ -382,17 +399,22 @@ class ShowWorker(QtCore.QThread):
|
||||
|
||||
self.progressbar_show.emit(True)
|
||||
self.info_label.emit(translate("AddonsInstaller", "Retrieving description..."))
|
||||
|
||||
if len(self.repos[self.idx]) == 4:
|
||||
desc = self.repos[self.idx][3]
|
||||
else:
|
||||
u = None
|
||||
url = self.repos[self.idx][1]
|
||||
if url in url_to_branch_map:
|
||||
branch = url_to_branch_map[url]
|
||||
else:
|
||||
branch = "master"
|
||||
self.info_label.emit(translate("AddonsInstaller", "Retrieving info from") + " " + str(url))
|
||||
desc = ""
|
||||
regex = utils.get_readme_regex(url)
|
||||
if regex:
|
||||
# extract readme from html via regex
|
||||
readmeurl = utils.get_readme_html_url(url)
|
||||
readmeurl = utils.get_readme_html_url(url,branch)
|
||||
if not readmeurl:
|
||||
print("Debug: README not found for", url)
|
||||
u = utils.urlopen(readmeurl)
|
||||
@@ -411,7 +433,7 @@ class ShowWorker(QtCore.QThread):
|
||||
print("Debug: README not found at", readmeurl)
|
||||
else:
|
||||
# convert raw markdown using lib
|
||||
readmeurl = utils.get_readme_url(url)
|
||||
readmeurl = utils.get_readme_url(url,branch)
|
||||
if not readmeurl:
|
||||
print("Debug: README not found for", url)
|
||||
u = utils.urlopen(readmeurl)
|
||||
@@ -421,7 +443,7 @@ class ShowWorker(QtCore.QThread):
|
||||
p = p.decode("utf-8")
|
||||
u.close()
|
||||
desc = utils.fix_relative_links(p, readmeurl.rsplit("/README.md")[0])
|
||||
if NOMARKDOWN or not have_markdown:
|
||||
if have_markdown and not NOMARKDOWN:
|
||||
desc = markdown.markdown(desc, extensions=["md_in_html"])
|
||||
else:
|
||||
message = """
|
||||
@@ -863,7 +885,11 @@ class InstallWorker(QtCore.QThread):
|
||||
shutil.rmtree(bakdir)
|
||||
os.rename(clonedir, bakdir)
|
||||
os.makedirs(clonedir)
|
||||
zipurl = utils.get_zip_url(baseurl)
|
||||
if baseurl in url_to_branch_map:
|
||||
branch = url_to_branch_map[baseurl]
|
||||
else:
|
||||
branch = "master"
|
||||
zipurl = utils.get_zip_url(baseurl, branch)
|
||||
if not zipurl:
|
||||
return translate("AddonsInstaller", "Error: Unable to locate zip from") + " " + baseurl
|
||||
try:
|
||||
|
||||
@@ -645,18 +645,20 @@ class _ArchMaterialTaskPanel:
|
||||
self.material["Father"] = text
|
||||
|
||||
def getColor(self):
|
||||
"opens a color picker dialog"
|
||||
color = QtGui.QColorDialog.getColor()
|
||||
colorPix = QtGui.QPixmap(16,16)
|
||||
colorPix.fill(color)
|
||||
self.form.ButtonColor.setIcon(QtGui.QIcon(colorPix))
|
||||
self.getColorForButton(self.form.ButtonColor)
|
||||
|
||||
def getSectionColor(self):
|
||||
self.getColorForButton(self.form.ButtonSectionColor)
|
||||
|
||||
def getColorForButton(self,button):
|
||||
"opens a color picker dialog"
|
||||
color = QtGui.QColorDialog.getColor()
|
||||
colorPix = QtGui.QPixmap(16,16)
|
||||
colorPix.fill(color)
|
||||
self.form.ButtonSectionColor.setIcon(QtGui.QIcon(colorPix))
|
||||
icon = button.icon()
|
||||
pixel = icon.pixmap(16,16).toImage().pixel(0,0)
|
||||
color = QtGui.QColorDialog.getColor(QtGui.QColor(pixel))
|
||||
if color.isValid():
|
||||
colorPix = QtGui.QPixmap(16,16)
|
||||
colorPix.fill(color)
|
||||
button.setIcon(QtGui.QIcon(colorPix))
|
||||
|
||||
def fillMaterialCombo(self):
|
||||
"fills the combo with the existing FCMat cards"
|
||||
|
||||
@@ -211,11 +211,11 @@ def getCutShapes(objs,cutplane,onlySolids,clip,joinArch,showHidden,groupSshapesB
|
||||
|
||||
cutface,cutvolume,invcutvolume = ArchCommands.getCutVolume(cutplane,shapes,clip)
|
||||
shapes = []
|
||||
if cutvolume:
|
||||
for o, shapeList in objectShapes:
|
||||
tmpSshapes = []
|
||||
for sh in shapeList:
|
||||
for sol in sh.Solids:
|
||||
for o, shapeList in objectShapes:
|
||||
tmpSshapes = []
|
||||
for sh in shapeList:
|
||||
for sol in sh.Solids:
|
||||
if cutvolume:
|
||||
if sol.Volume < 0:
|
||||
sol.reverse()
|
||||
c = sol.cut(cutvolume)
|
||||
@@ -235,6 +235,8 @@ def getCutShapes(objs,cutplane,onlySolids,clip,joinArch,showHidden,groupSshapesB
|
||||
if showHidden:
|
||||
c = sol.cut(invcutvolume)
|
||||
hshapes.append(c)
|
||||
else:
|
||||
shapes.extend(sol.Solids)
|
||||
|
||||
if len(tmpSshapes) > 0:
|
||||
sshapes.extend(tmpSshapes)
|
||||
|
||||
@@ -632,7 +632,10 @@ class _Window(ArchComponent.Component):
|
||||
elif "Edge" in s:
|
||||
hinge = int(s[4:])-1
|
||||
elif "Mode" in s:
|
||||
omode = int(s[-1])
|
||||
omode = int(s[4:])
|
||||
if omode >= len(WindowOpeningModes):
|
||||
# Ignore modes not listed in WindowOpeningModes
|
||||
omode = None
|
||||
if wires:
|
||||
max_length = 0
|
||||
for w in wires:
|
||||
@@ -1506,7 +1509,11 @@ class _ArchWindowTaskPanel:
|
||||
elif "Edge" in l:
|
||||
self.field6.setText(l)
|
||||
elif "Mode" in l:
|
||||
self.field7.setCurrentIndex(int(l[-1]))
|
||||
if int(l[4:]) < len(WindowOpeningModes):
|
||||
self.field7.setCurrentIndex(int(l[4:]))
|
||||
else:
|
||||
# Ignore modes not listed in WindowOpeningModes
|
||||
self.field7.setCurrentIndex(0)
|
||||
if wires:
|
||||
f.setText(",".join(wires))
|
||||
|
||||
|
||||
@@ -340,6 +340,7 @@ def init_draft_statusbar_snap():
|
||||
|
||||
# add snap widget to the statusbar
|
||||
sb.insertPermanentWidget(2, snap_widget)
|
||||
snap_widget.setOrientation(QtCore.Qt.Orientation.Horizontal)
|
||||
snap_widget.show()
|
||||
|
||||
|
||||
@@ -373,11 +374,13 @@ def show_draft_statusbar():
|
||||
|
||||
snap_widget = sb.findChild(QtGui.QToolBar,"draft_snap_widget")
|
||||
if snap_widget:
|
||||
snap_widget.setOrientation(QtCore.Qt.Orientation.Horizontal)
|
||||
snap_widget.show()
|
||||
else:
|
||||
snap_widget = mw.findChild(QtGui.QToolBar,"draft_snap_widget")
|
||||
if snap_widget:
|
||||
sb.insertPermanentWidget(2, snap_widget)
|
||||
snap_widget.setOrientation(QtCore.Qt.Orientation.Horizontal)
|
||||
snap_widget.show()
|
||||
elif params.GetBool("DisplayStatusbarSnapWidget", True):
|
||||
t = QtCore.QTimer()
|
||||
|
||||
@@ -55,7 +55,7 @@ import six
|
||||
import FreeCAD
|
||||
import Part, Draft, Mesh
|
||||
import DraftVecUtils, DraftGeomUtils, WorkingPlane
|
||||
from Draft import _Dimension, _ViewProviderDimension
|
||||
from Draft import _Dimension
|
||||
from FreeCAD import Vector
|
||||
from FreeCAD import Console as FCC
|
||||
|
||||
@@ -2573,7 +2573,9 @@ def processdxf(document, filename, getShapes=False, reComputeFlag=True):
|
||||
newob = doc.addObject("App::FeaturePython", "Dimension")
|
||||
lay.addObject(newob)
|
||||
_Dimension(newob)
|
||||
_ViewProviderDimension(newob.ViewObject)
|
||||
if FreeCAD.GuiUp:
|
||||
from Draft import _ViewProviderDimension
|
||||
_ViewProviderDimension(newob.ViewObject)
|
||||
newob.Start = p1
|
||||
newob.End = p2
|
||||
newob.Dimline = pt
|
||||
|
||||
@@ -246,7 +246,7 @@
|
||||
<double>2.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum" stdset="0">
|
||||
<double>2000000000.000000000000000</double>
|
||||
<double>90000000000.000000000000000</double>
|
||||
</property>
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true">Pa</string>
|
||||
|
||||
@@ -162,7 +162,7 @@ def read(
|
||||
or fileExtension.lower() == ".yml"
|
||||
) and has_yaml:
|
||||
fp = pyopen(fileString, "rt")
|
||||
raw_mesh_data = yaml.load(fp)
|
||||
raw_mesh_data = yaml.load(fp, Loader=yaml.SafeLoader)
|
||||
fp.close()
|
||||
else:
|
||||
Console.PrintError(
|
||||
|
||||
@@ -30,6 +30,12 @@ __url__ = "https://www.freecadweb.org"
|
||||
# \ingroup FEM
|
||||
# \brief task panel for mechanical ResultObjectPython
|
||||
|
||||
try:
|
||||
import matplotlib
|
||||
matplotlib.use("Qt5Agg")
|
||||
except Exception:
|
||||
print("Failed to set matplotlib backend to Qt5Agg")
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
|
||||
@@ -82,6 +82,8 @@
|
||||
|
||||
#include "ImpExpDxf.h"
|
||||
|
||||
namespace Import {
|
||||
|
||||
class ImportOCAFExt : public Import::ImportOCAF2
|
||||
{
|
||||
public:
|
||||
@@ -98,7 +100,6 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
namespace Import {
|
||||
class Module : public Py::ExtensionModule<Module>
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
# include <TDF_LabelSequence.hxx>
|
||||
# include <TDF_ChildIterator.hxx>
|
||||
# include <TDataStd_Name.hxx>
|
||||
# include <Quantity_Color.hxx>
|
||||
# include <Quantity_ColorRGBA.hxx>
|
||||
# include <STEPCAFControl_Reader.hxx>
|
||||
# include <STEPControl_Writer.hxx>
|
||||
# include <IGESCAFControl_Reader.hxx>
|
||||
@@ -95,6 +95,17 @@
|
||||
#include <App/DocumentObject.h>
|
||||
#include <App/DocumentObjectGroup.h>
|
||||
|
||||
#if OCC_VERSION_HEX >= 0x070500
|
||||
// See https://dev.opencascade.org/content/occt-3d-viewer-becomes-srgb-aware
|
||||
# define OCC_COLOR_SPACE Quantity_TOC_sRGB
|
||||
#else
|
||||
# define OCC_COLOR_SPACE Quantity_TOC_RGB
|
||||
#endif
|
||||
|
||||
static inline Quantity_ColorRGBA convertColor(const App::Color &c)
|
||||
{
|
||||
return Quantity_ColorRGBA(Quantity_Color(c.r, c.g, c.b, OCC_COLOR_SPACE), 1.0 - c.a);
|
||||
}
|
||||
|
||||
using namespace Import;
|
||||
|
||||
@@ -284,7 +295,7 @@ int ExportOCAF::saveShape(Part::Feature* part, const std::vector<App::Color>& co
|
||||
*/
|
||||
|
||||
// Add color information
|
||||
Quantity_Color col;
|
||||
Quantity_ColorRGBA col;
|
||||
|
||||
std::set<int> face_index;
|
||||
TopTools_IndexedMapOfShape faces;
|
||||
@@ -317,11 +328,7 @@ int ExportOCAF::saveShape(Part::Feature* part, const std::vector<App::Color>& co
|
||||
|
||||
if (!faceLabel.IsNull()) {
|
||||
const App::Color& color = colors[index-1];
|
||||
Standard_Real mat[3];
|
||||
mat[0] = color.r;
|
||||
mat[1] = color.g;
|
||||
mat[2] = color.b;
|
||||
col.SetValues(mat[0],mat[1],mat[2],Quantity_TOC_RGB);
|
||||
col = convertColor(color);
|
||||
aColorTool->SetColor(faceLabel, col, XCAFDoc_ColorSurf);
|
||||
}
|
||||
}
|
||||
@@ -330,11 +337,7 @@ int ExportOCAF::saveShape(Part::Feature* part, const std::vector<App::Color>& co
|
||||
}
|
||||
else if (!colors.empty()) {
|
||||
App::Color color = colors.front();
|
||||
Standard_Real mat[3];
|
||||
mat[0] = color.r;
|
||||
mat[1] = color.g;
|
||||
mat[2] = color.b;
|
||||
col.SetValues(mat[0],mat[1],mat[2],Quantity_TOC_RGB);
|
||||
col = convertColor(color);
|
||||
aColorTool->SetColor(shapeLabel, col, XCAFDoc_ColorGen);
|
||||
}
|
||||
|
||||
@@ -400,7 +403,7 @@ void ExportOCAF::reallocateFreeShape(std::vector <App::DocumentObject*> hierarch
|
||||
TopoDS_Shape baseShape = part->Shape.getValue();
|
||||
|
||||
// Add color information
|
||||
Quantity_Color col;
|
||||
Quantity_ColorRGBA col;
|
||||
|
||||
std::set<int> face_index;
|
||||
TopTools_IndexedMapOfShape faces;
|
||||
@@ -433,11 +436,7 @@ void ExportOCAF::reallocateFreeShape(std::vector <App::DocumentObject*> hierarch
|
||||
|
||||
if (!faceLabel.IsNull()) {
|
||||
const App::Color& color = colors[index-1];
|
||||
Standard_Real mat[3];
|
||||
mat[0] = color.r;
|
||||
mat[1] = color.g;
|
||||
mat[2] = color.b;
|
||||
col.SetValues(mat[0],mat[1],mat[2],Quantity_TOC_RGB);
|
||||
col = convertColor(color);
|
||||
aColorTool->SetColor(faceLabel, col, XCAFDoc_ColorSurf);
|
||||
}
|
||||
}
|
||||
@@ -447,11 +446,7 @@ void ExportOCAF::reallocateFreeShape(std::vector <App::DocumentObject*> hierarch
|
||||
}
|
||||
else if (!colors.empty()) {
|
||||
App::Color color = colors.front();
|
||||
Standard_Real mat[3];
|
||||
mat[0] = color.r;
|
||||
mat[1] = color.g;
|
||||
mat[2] = color.b;
|
||||
col.SetValues(mat[0],mat[1],mat[2],Quantity_TOC_RGB);
|
||||
col = convertColor(color);
|
||||
aColorTool->SetColor(label, col, XCAFDoc_ColorGen);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
# include <TDF_LabelSequence.hxx>
|
||||
# include <TDF_ChildIterator.hxx>
|
||||
# include <TDataStd_Name.hxx>
|
||||
# include <Quantity_Color.hxx>
|
||||
# include <Quantity_ColorRGBA.hxx>
|
||||
# include <STEPCAFControl_Reader.hxx>
|
||||
# include <STEPControl_Writer.hxx>
|
||||
# include <IGESCAFControl_Reader.hxx>
|
||||
@@ -108,6 +108,23 @@
|
||||
|
||||
using namespace Import;
|
||||
|
||||
#if OCC_VERSION_HEX >= 0x070500
|
||||
// See https://dev.opencascade.org/content/occt-3d-viewer-becomes-srgb-aware
|
||||
# define OCC_COLOR_SPACE Quantity_TOC_sRGB
|
||||
#else
|
||||
# define OCC_COLOR_SPACE Quantity_TOC_RGB
|
||||
#endif
|
||||
|
||||
static inline App::Color convertColor(const Quantity_ColorRGBA &c)
|
||||
{
|
||||
Standard_Real r, g, b;
|
||||
c.GetRGB().Values(r, g, b, OCC_COLOR_SPACE);
|
||||
return App::Color(static_cast<float>(r),
|
||||
static_cast<float>(g),
|
||||
static_cast<float>(b),
|
||||
1.0f - static_cast<float>(c.Alpha()));
|
||||
}
|
||||
|
||||
#define OCAF_KEEP_PLACEMENT
|
||||
|
||||
ImportOCAF::ImportOCAF(Handle(TDocStd_Document) h, App::Document* d, const std::string& name)
|
||||
@@ -439,14 +456,12 @@ void ImportOCAF::createShape(const TopoDS_Shape& aShape, const TopLoc_Location&
|
||||
|
||||
void ImportOCAF::loadColors(Part::Feature* part, const TopoDS_Shape& aShape)
|
||||
{
|
||||
Quantity_Color aColor;
|
||||
Quantity_ColorRGBA aColor;
|
||||
App::Color color(0.8f,0.8f,0.8f);
|
||||
if (aColorTool->GetColor(aShape, XCAFDoc_ColorGen, aColor) ||
|
||||
aColorTool->GetColor(aShape, XCAFDoc_ColorSurf, aColor) ||
|
||||
aColorTool->GetColor(aShape, XCAFDoc_ColorCurv, aColor)) {
|
||||
color.r = (float)aColor.Red();
|
||||
color.g = (float)aColor.Green();
|
||||
color.b = (float)aColor.Blue();
|
||||
color = convertColor(aColor);
|
||||
std::vector<App::Color> colors;
|
||||
colors.push_back(color);
|
||||
applyColors(part, colors);
|
||||
@@ -468,9 +483,7 @@ void ImportOCAF::loadColors(Part::Feature* part, const TopoDS_Shape& aShape)
|
||||
aColorTool->GetColor(xp.Current(), XCAFDoc_ColorSurf, aColor) ||
|
||||
aColorTool->GetColor(xp.Current(), XCAFDoc_ColorCurv, aColor)) {
|
||||
int index = faces.FindIndex(xp.Current());
|
||||
color.r = (float)aColor.Red();
|
||||
color.g = (float)aColor.Green();
|
||||
color.b = (float)aColor.Blue();
|
||||
color = convertColor(aColor);
|
||||
faceColors[index-1] = color;
|
||||
found_face_color = true;
|
||||
}
|
||||
@@ -551,7 +564,7 @@ void ImportXCAF::createShape(const TopoDS_Shape& shape, bool perface, bool setna
|
||||
part = static_cast<Part::Feature*>(doc->addObject("Part::Feature", default_name.c_str()));
|
||||
part->Label.setValue(default_name);
|
||||
part->Shape.setValue(shape);
|
||||
std::map<Standard_Integer, Quantity_Color>::const_iterator jt;
|
||||
std::map<Standard_Integer, Quantity_ColorRGBA>::const_iterator jt;
|
||||
jt = myColorMap.find(shape.HashCode(INT_MAX));
|
||||
|
||||
App::Color partColor(0.8f,0.8f,0.8f);
|
||||
@@ -596,11 +609,7 @@ void ImportXCAF::createShape(const TopoDS_Shape& shape, bool perface, bool setna
|
||||
jt = myColorMap.find(xp.Current().HashCode(INT_MAX));
|
||||
if (jt != myColorMap.end()) {
|
||||
int index = faces.FindIndex(xp.Current());
|
||||
App::Color color;
|
||||
color.r = (float)jt->second.Red();
|
||||
color.g = (float)jt->second.Green();
|
||||
color.b = (float)jt->second.Blue();
|
||||
faceColors[index-1] = color;
|
||||
faceColors[index-1] = convertColor(jt->second);
|
||||
found_face_color = true;
|
||||
}
|
||||
xp.Next();
|
||||
@@ -653,7 +662,7 @@ void ImportXCAF::loadShapes(const TDF_Label& label)
|
||||
}
|
||||
|
||||
// getting color
|
||||
Quantity_Color col;
|
||||
Quantity_ColorRGBA col;
|
||||
if (hColors->GetColor(label, XCAFDoc_ColorGen, col) ||
|
||||
hColors->GetColor(label, XCAFDoc_ColorSurf, col) ||
|
||||
hColors->GetColor(label, XCAFDoc_ColorCurv, col)) {
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include <TDocStd_Document.hxx>
|
||||
#include <XCAFDoc_ColorTool.hxx>
|
||||
#include <XCAFDoc_ShapeTool.hxx>
|
||||
#include <Quantity_Color.hxx>
|
||||
#include <Quantity_ColorRGBA.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
#include <TDF_LabelMapHasher.hxx>
|
||||
#include <climits>
|
||||
@@ -117,7 +117,7 @@ private:
|
||||
std::map<Standard_Integer, TopoDS_Shape> myShells;
|
||||
std::map<Standard_Integer, TopoDS_Shape> myCompds;
|
||||
std::map<Standard_Integer, TopoDS_Shape> myShapes;
|
||||
std::map<Standard_Integer, Quantity_Color> myColorMap;
|
||||
std::map<Standard_Integer, Quantity_ColorRGBA> myColorMap;
|
||||
std::map<Standard_Integer, std::string> myNameMap;
|
||||
};
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
# include <TDF_LabelSequence.hxx>
|
||||
# include <TDF_ChildIterator.hxx>
|
||||
# include <TDataStd_Name.hxx>
|
||||
# include <Quantity_Color.hxx>
|
||||
# include <Quantity_ColorRGBA.hxx>
|
||||
# include <TopoDS_Iterator.hxx>
|
||||
# include <Interface_Static.hxx>
|
||||
# include <TDF_AttributeSequence.hxx>
|
||||
@@ -50,6 +50,7 @@
|
||||
|
||||
#include <XCAFDoc_ShapeMapTool.hxx>
|
||||
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <Base/Parameter.h>
|
||||
@@ -71,12 +72,40 @@
|
||||
#include <App/DocumentObject.h>
|
||||
#include <App/DocumentObjectGroup.h>
|
||||
|
||||
#if OCC_VERSION_HEX >= 0x070500
|
||||
// See https://dev.opencascade.org/content/occt-3d-viewer-becomes-srgb-aware
|
||||
# define OCC_COLOR_SPACE Quantity_TOC_sRGB
|
||||
#else
|
||||
# define OCC_COLOR_SPACE Quantity_TOC_RGB
|
||||
#endif
|
||||
|
||||
FC_LOG_LEVEL_INIT("Import",true,true)
|
||||
|
||||
using namespace Import;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
static inline App::Color convertColor(const Quantity_ColorRGBA &c)
|
||||
{
|
||||
Standard_Real r, g, b;
|
||||
c.GetRGB().Values(r, g, b, OCC_COLOR_SPACE);
|
||||
return App::Color(static_cast<float>(r),
|
||||
static_cast<float>(g),
|
||||
static_cast<float>(b),
|
||||
1.0f - static_cast<float>(c.Alpha()));
|
||||
}
|
||||
|
||||
static inline Quantity_ColorRGBA convertColor(const App::Color &c)
|
||||
{
|
||||
return Quantity_ColorRGBA(Quantity_Color(c.r, c.g, c.b, OCC_COLOR_SPACE), 1.0f - c.a);
|
||||
}
|
||||
|
||||
static inline std::ostream& operator<<(std::ostream& os, const Quantity_ColorRGBA &c) {
|
||||
App::Color color = convertColor(c);
|
||||
auto toHex = [](float v) {return boost::format("%02X") % static_cast<int>(v*255);};
|
||||
return os << "#" << toHex(color.r) << toHex(color.g) << toHex(color.b) << toHex(color.a);
|
||||
}
|
||||
|
||||
static std::string labelName(TDF_Label label) {
|
||||
std::string txt;
|
||||
Handle(TDataStd_Name) name;
|
||||
@@ -116,13 +145,13 @@ static void printLabel(TDF_Label label, Handle(XCAFDoc_ShapeTool) aShapeTool,
|
||||
ss << ", " << Part::TopoShape::shapeName(shape.ShapeType(),true);
|
||||
}
|
||||
if(aShapeTool->IsShape(label)) {
|
||||
Quantity_Color c;
|
||||
Quantity_ColorRGBA c;
|
||||
if(aColorTool->GetColor(label,XCAFDoc_ColorGen,c))
|
||||
ss << ", gc: " << c.StringName(c.Name());
|
||||
ss << ", gc: " << c;
|
||||
if(aColorTool->GetColor(label,XCAFDoc_ColorSurf,c))
|
||||
ss << ", sc: " << c.StringName(c.Name());
|
||||
ss << ", sc: " << c;
|
||||
if(aColorTool->GetColor(label,XCAFDoc_ColorCurv,c))
|
||||
ss << ", cc: " << c.StringName(c.Name());
|
||||
ss << ", cc: " << c;
|
||||
}
|
||||
|
||||
ss << std::endl;
|
||||
@@ -229,12 +258,11 @@ void ImportOCAF2::setObjectName(Info &info, TDF_Label label) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ImportOCAF2::getColor(const TopoDS_Shape &shape, Info &info, bool check, bool noDefault) {
|
||||
bool ret = false;
|
||||
Quantity_Color aColor;
|
||||
Quantity_ColorRGBA aColor;
|
||||
if(aColorTool->GetColor(shape, XCAFDoc_ColorSurf, aColor)) {
|
||||
App::Color c(aColor.Red(),aColor.Green(),aColor.Blue());
|
||||
App::Color c = convertColor(aColor);
|
||||
if(!check || info.faceColor!=c) {
|
||||
info.faceColor = c;
|
||||
info.hasFaceColor = true;
|
||||
@@ -242,7 +270,7 @@ bool ImportOCAF2::getColor(const TopoDS_Shape &shape, Info &info, bool check, bo
|
||||
}
|
||||
}
|
||||
if(!noDefault && !info.hasFaceColor && aColorTool->GetColor(shape, XCAFDoc_ColorGen, aColor)) {
|
||||
App::Color c(aColor.Red(),aColor.Green(),aColor.Blue());
|
||||
App::Color c = convertColor(aColor);
|
||||
if(!check || info.faceColor!=c) {
|
||||
info.faceColor = c;
|
||||
info.hasFaceColor = true;
|
||||
@@ -250,7 +278,7 @@ bool ImportOCAF2::getColor(const TopoDS_Shape &shape, Info &info, bool check, bo
|
||||
}
|
||||
}
|
||||
if(aColorTool->GetColor(shape, XCAFDoc_ColorCurv, aColor)) {
|
||||
App::Color c(aColor.Red(),aColor.Green(),aColor.Blue());
|
||||
App::Color c = convertColor(aColor);
|
||||
// Some STEP include a curve color with the same value of the face
|
||||
// color. And this will look weird in FC. So for shape with face
|
||||
// we'll ignore the curve color, if it is the same as the face color.
|
||||
@@ -365,15 +393,15 @@ bool ImportOCAF2::createObject(App::Document *doc, TDF_Label label,
|
||||
|
||||
bool foundFaceColor=false,foundEdgeColor=false;
|
||||
App::Color faceColor,edgeColor;
|
||||
Quantity_Color aColor;
|
||||
Quantity_ColorRGBA aColor;
|
||||
if(aColorTool->GetColor(l, XCAFDoc_ColorSurf, aColor) ||
|
||||
aColorTool->GetColor(l, XCAFDoc_ColorGen, aColor))
|
||||
{
|
||||
faceColor = App::Color(aColor.Red(),aColor.Green(),aColor.Blue());
|
||||
faceColor = convertColor(aColor);
|
||||
foundFaceColor = true;
|
||||
}
|
||||
if(aColorTool->GetColor(l, XCAFDoc_ColorCurv, aColor)) {
|
||||
edgeColor = App::Color(aColor.Red(),aColor.Green(),aColor.Blue());
|
||||
edgeColor = convertColor(aColor);
|
||||
foundEdgeColor = true;
|
||||
if(j==0 && foundFaceColor && faceColors.size() && edgeColor==faceColor) {
|
||||
// Do not set edge the same color as face
|
||||
@@ -648,11 +676,11 @@ void ImportOCAF2::getSHUOColors(TDF_Label label,
|
||||
subname += App::DocumentObject::hiddenMarker();
|
||||
colors.emplace(subname,App::Color());
|
||||
} else {
|
||||
Quantity_Color aColor;
|
||||
Quantity_ColorRGBA aColor;
|
||||
if(aColorTool->GetColor(slabel, XCAFDoc_ColorSurf, aColor) ||
|
||||
aColorTool->GetColor(slabel, XCAFDoc_ColorGen, aColor))
|
||||
{
|
||||
colors.emplace(subname,App::Color(aColor.Red(),aColor.Green(),aColor.Blue()));
|
||||
colors.emplace(subname,convertColor(aColor));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -782,12 +810,9 @@ bool ImportOCAF2::createAssembly(App::Document *_doc,
|
||||
childInfo.vis.push_back(vis);
|
||||
childInfo.labels.push_back(childLabel);
|
||||
childInfo.plas.emplace_back(Part::TopoShape::convert(childShape.Location().Transformation()));
|
||||
Quantity_Color aColor;
|
||||
Quantity_ColorRGBA aColor;
|
||||
if (aColorTool->GetColor(childShape, XCAFDoc_ColorSurf, aColor)) {
|
||||
auto &color = childInfo.colors[childInfo.plas.size()-1];
|
||||
color.r = (float)aColor.Red();
|
||||
color.g = (float)aColor.Green();
|
||||
color.b = (float)aColor.Blue();
|
||||
childInfo.colors[childInfo.plas.size()-1] = convertColor(aColor);
|
||||
}
|
||||
}
|
||||
assert(visibilities.size() == children.size());
|
||||
@@ -1036,7 +1061,7 @@ void ExportOCAF2::setupObject(TDF_Label label, App::DocumentObject *obj,
|
||||
continue;
|
||||
}
|
||||
const App::Color& c = vv.second;
|
||||
Quantity_Color color(c.r,c.g,c.b,Quantity_TOC_RGB);
|
||||
Quantity_ColorRGBA color = convertColor(c);
|
||||
auto colorType = vv.first[0]=='F'?XCAFDoc_ColorSurf:XCAFDoc_ColorCurv;
|
||||
if(vv.first=="Face" || vv.first=="Edge") {
|
||||
aColorTool->SetColor(nodeLabel, color, colorType);
|
||||
@@ -1219,8 +1244,17 @@ TDF_Label ExportOCAF2::exportObject(App::DocumentObject* parentObj,
|
||||
// not call setupObject() on a non-located baseshape like above,
|
||||
// because OCCT does not respect shape style sharing when not
|
||||
// exporting assembly
|
||||
if(!keepPlacement)
|
||||
if(!keepPlacement || shape.getPlacement() == Base::Placement())
|
||||
shape.setShape(shape.getShape().Located(TopLoc_Location()));
|
||||
else {
|
||||
Base::Matrix4D mat = shape.getTransform();
|
||||
shape.setShape(shape.getShape().Located(TopLoc_Location()));
|
||||
// Transform with copy to conceal the transformation
|
||||
shape.transformShape(mat, true);
|
||||
// Even if the shape has no transformation, TopoShape still sets
|
||||
// a TopLoc_Location, so we need to clear it again.
|
||||
shape.setShape(shape.getShape().Located(TopLoc_Location()));
|
||||
}
|
||||
label = aShapeTool->AddShape(shape.getShape(),Standard_False, Standard_False);
|
||||
auto o = name?parentObj:obj;
|
||||
if(o!=linked)
|
||||
@@ -1277,7 +1311,7 @@ TDF_Label ExportOCAF2::exportObject(App::DocumentObject* parentObj,
|
||||
// Work around OCCT bug. If no color setting here, it will crash.
|
||||
// The culprit is at STEPCAFControl_Writer::1093 as shown below
|
||||
//
|
||||
// surfColor = Styles.EncodeColor(Quantity_Color(1,1,1,Quantity_TOC_RGB),DPDCs,ColRGBs);
|
||||
// surfColor = Styles.EncodeColor(Quantity_Color(1,1,1,OCC_COLOR_SPACE),DPDCs,ColRGBs);
|
||||
// PSA = Styles.MakeColorPSA ( item, surfColor, curvColor, isComponent );
|
||||
// if ( isComponent )
|
||||
// setDefaultInstanceColor( override, PSA);
|
||||
@@ -1287,13 +1321,13 @@ TDF_Label ExportOCAF2::exportObject(App::DocumentObject* parentObj,
|
||||
// setDefaultInstanceColor( override, PSA);
|
||||
//
|
||||
auto childShape = aShapeTool->GetShape(childLabel);
|
||||
Quantity_Color col;
|
||||
Quantity_ColorRGBA col;
|
||||
if(!aColorTool->GetInstanceColor(childShape,XCAFDoc_ColorGen,col) &&
|
||||
!aColorTool->GetInstanceColor(childShape,XCAFDoc_ColorSurf,col) &&
|
||||
!aColorTool->GetInstanceColor(childShape,XCAFDoc_ColorCurv,col))
|
||||
{
|
||||
auto &c = defaultColor;
|
||||
aColorTool->SetColor(childLabel, Quantity_Color(c.r,c.g,c.b,Quantity_TOC_RGB), XCAFDoc_ColorGen);
|
||||
aColorTool->SetColor(childLabel, convertColor(c), XCAFDoc_ColorGen);
|
||||
FC_WARN(labelName(childLabel) << " set default color");
|
||||
}
|
||||
aColorTool->SetVisibility(childLabel,Standard_False);
|
||||
|
||||
@@ -138,6 +138,7 @@
|
||||
|
||||
FC_LOG_LEVEL_INIT("Import", true, true)
|
||||
|
||||
namespace ImportGui {
|
||||
class OCAFBrowser
|
||||
{
|
||||
public:
|
||||
@@ -321,9 +322,10 @@ private:
|
||||
return;
|
||||
}
|
||||
// vp->MapFaceColor.setValue(false);
|
||||
if(colors.size() == 1)
|
||||
if(colors.size() == 1) {
|
||||
vp->ShapeColor.setValue(colors.front());
|
||||
else
|
||||
vp->Transparency.setValue(100 * colors.front().a);
|
||||
} else
|
||||
vp->DiffuseColor.setValues(colors);
|
||||
}
|
||||
virtual void applyEdgeColors(Part::Feature* part, const std::vector<App::Color>& colors) override {
|
||||
@@ -382,7 +384,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
namespace ImportGui {
|
||||
class Module : public Py::ExtensionModule<Module>
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
[General]
|
||||
Name = Air
|
||||
Description = Standard air properties at 20 Degrees Celsius and 1 atm
|
||||
Description = Dry air properties at 20 Degrees Celsius and 1 atm
|
||||
MolarMass = 28.965
|
||||
Father = Gas
|
||||
|
||||
[Fluidic]
|
||||
Density = 1.20 kg/m^3
|
||||
Density = 1.204 kg/m^3
|
||||
DynamicViscosity = 1.80e-5 kg/m/s
|
||||
KinematicViscosity = 1.511e-5 m^2/s
|
||||
; PrandtlNumber is a nondimension number for CFD simulation
|
||||
PrandtlNumber = 0.7
|
||||
|
||||
[Thermal]
|
||||
SpecificHeat = 1.005 J/kg/K
|
||||
ThermalConductivity = 0.0257 W/m/K
|
||||
SpecificHeat = 1.01 kJ/kg/K
|
||||
ThermalConductivity = 0.02587 W/m/K
|
||||
; volumetric expansion coeff of ideal gas depends on temperature and pressure
|
||||
VolumetricThermalExpansionCoefficient = 3.43e-3 m/m/K
|
||||
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
# include <Standard_Failure.hxx>
|
||||
#endif
|
||||
|
||||
// Needed for OCCT 7.5.2
|
||||
#include <TopoDS_Edge.hxx>
|
||||
|
||||
#include "ShapeUpgrade/UnifySameDomainPy.h"
|
||||
#include "ShapeUpgrade/UnifySameDomainPy.cpp"
|
||||
#include "TopoShapePy.h"
|
||||
|
||||
@@ -977,13 +977,14 @@ Py::Object TopoShapeFacePy::getWire(void) const
|
||||
|
||||
Py::Object TopoShapeFacePy::getOuterWire(void) const
|
||||
{
|
||||
const TopoDS_Shape& clSh = getTopoShapePtr()->getShape();
|
||||
if (clSh.IsNull())
|
||||
const TopoDS_Shape& shape = getTopoShapePtr()->getShape();
|
||||
if (shape.IsNull())
|
||||
throw Py::RuntimeError("Null shape");
|
||||
if (clSh.ShapeType() == TopAbs_FACE) {
|
||||
TopoDS_Face clFace = (TopoDS_Face&)clSh;
|
||||
TopoDS_Wire clWire = ShapeAnalysis::OuterWire(clFace);
|
||||
return Py::Object(new TopoShapeWirePy(new TopoShape(clWire)),true);
|
||||
if (shape.ShapeType() == TopAbs_FACE) {
|
||||
TopoDS_Wire wire = ShapeAnalysis::OuterWire(TopoDS::Face(shape));
|
||||
Base::PyObjectBase* wirepy = new TopoShapeWirePy(new TopoShape(wire));
|
||||
wirepy->setNotTracking();
|
||||
return Py::asObject(wirepy);
|
||||
}
|
||||
else {
|
||||
throw Py::TypeError("Internal error, TopoDS_Shape is not a face!");
|
||||
|
||||
@@ -194,7 +194,9 @@ Py::Object TopoShapeVertexPy::getPoint(void) const
|
||||
try {
|
||||
const TopoDS_Vertex& v = TopoDS::Vertex(getTopoShapePtr()->getShape());
|
||||
gp_Pnt p = BRep_Tool::Pnt(v);
|
||||
return Py::asObject(new Base::VectorPy(new Base::Vector3d(p.X(),p.Y(),p.Z())));
|
||||
Base::PyObjectBase* pnt = new Base::VectorPy(new Base::Vector3d(p.X(),p.Y(),p.Z()));
|
||||
pnt->setNotTracking();
|
||||
return Py::asObject(pnt);
|
||||
}
|
||||
catch (Standard_Failure& e) {
|
||||
|
||||
|
||||
@@ -274,7 +274,7 @@ void ViewProvider2DObjectGrid::onChanged(const App::Property* prop)
|
||||
ViewProviderPart::onChanged(prop);
|
||||
|
||||
if (prop == &ShowGrid || prop == &ShowOnlyInEditMode || prop == &Visibility) {
|
||||
if (ShowGrid.getValue() && Visibility.getValue() && !(ShowOnlyInEditMode.getValue() && !this->isEditing()))
|
||||
if (ShowGrid.getValue() && ((Visibility.getValue() && !ShowOnlyInEditMode.getValue()) || this->isEditing()))
|
||||
createGrid();
|
||||
else
|
||||
Gui::coinRemoveAllChildren(GridRoot);
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef PARTGUI_IEWPROVIDER2DOBJECT_H
|
||||
#define PARTGUI_IEWPROVIDER2DOBJECT_H
|
||||
#ifndef PARTGUI_VIEWPROVIDER2DOBJECT_H
|
||||
#define PARTGUI_VIEWPROVIDER2DOBJECT_H
|
||||
|
||||
#include "ViewProvider.h"
|
||||
#include <App/PropertyUnits.h>
|
||||
@@ -103,5 +103,5 @@ typedef Gui::ViewProviderPythonFeatureT<ViewProvider2DObject> ViewProvider2DObje
|
||||
} // namespace PartGui
|
||||
|
||||
|
||||
#endif // PARTGUI_IEWPROVIDER2DOBJECT_H
|
||||
#endif // PARTGUI_VIEWPROVIDER2DOBJECT_H
|
||||
|
||||
|
||||
@@ -427,24 +427,19 @@ void ViewProviderPartExt::onChanged(const App::Property* prop)
|
||||
else if (prop == &ShapeMaterial || prop == &ShapeColor) {
|
||||
pcFaceBind->value = SoMaterialBinding::OVERALL;
|
||||
ViewProviderGeometryObject::onChanged(prop);
|
||||
DiffuseColor.setValue(ShapeColor.getValue());
|
||||
App::Color c = ShapeColor.getValue();
|
||||
c.a = Transparency.getValue()/100.0f;
|
||||
DiffuseColor.setValue(c);
|
||||
}
|
||||
else if (prop == &Transparency) {
|
||||
const App::Material& Mat = ShapeMaterial.getValue();
|
||||
long value = (long)(100*Mat.transparency);
|
||||
if (value != Transparency.getValue()) {
|
||||
float trans = Transparency.getValue()/100.0f;
|
||||
if (pcFaceBind->value.getValue() == SoMaterialBinding::PER_PART) {
|
||||
int cnt = pcShapeMaterial->diffuseColor.getNum();
|
||||
pcShapeMaterial->transparency.setNum(cnt);
|
||||
float *t = pcShapeMaterial->transparency.startEditing();
|
||||
for (int i=0; i<cnt; i++)
|
||||
t[i] = trans;
|
||||
pcShapeMaterial->transparency.finishEditing();
|
||||
}
|
||||
else {
|
||||
pcShapeMaterial->transparency = trans;
|
||||
}
|
||||
auto colors = DiffuseColor.getValues();
|
||||
for (auto &c : colors)
|
||||
c.a = trans;
|
||||
DiffuseColor.setValues(colors);
|
||||
|
||||
App::PropertyContainer* parent = ShapeMaterial.getContainer();
|
||||
ShapeMaterial.setContainer(0);
|
||||
@@ -713,7 +708,7 @@ void ViewProviderPartExt::setHighlightedFaces(const std::vector<App::Color>& col
|
||||
else if (colors.size() == 1) {
|
||||
pcFaceBind->value = SoMaterialBinding::OVERALL;
|
||||
pcShapeMaterial->diffuseColor.setValue(colors[0].r, colors[0].g, colors[0].b);
|
||||
//pcShapeMaterial->transparency = colors[0].a; do not get transparency from DiffuseColor in this case
|
||||
pcShapeMaterial->transparency = Transparency.getValue()/100.f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -779,6 +774,7 @@ std::map<std::string,App::Color> ViewProviderPartExt::getElementColors(const cha
|
||||
}
|
||||
if(size && singleColor) {
|
||||
color = DiffuseColor[0];
|
||||
color.a = Transparency.getValue()/100.0f;
|
||||
ret.clear();
|
||||
}
|
||||
ret["Face"] = color;
|
||||
|
||||
@@ -127,17 +127,17 @@ Gui::MenuItem* Workbench::setupMenuBar() const
|
||||
<< "Separator"
|
||||
<< bop << join << split << compound
|
||||
<< "Separator"
|
||||
<< "Part_Section"
|
||||
<< "Part_CrossSections"
|
||||
<< "Part_MakeFace"
|
||||
<< "Part_Extrude"
|
||||
<< "Part_Revolve"
|
||||
<< "Part_Mirror"
|
||||
<< "Part_Fillet"
|
||||
<< "Part_Chamfer"
|
||||
<< "Part_MakeFace"
|
||||
<< "Part_RuledSurface"
|
||||
<< "Part_Loft"
|
||||
<< "Part_Sweep"
|
||||
<< "Part_Section"
|
||||
<< "Part_CrossSections"
|
||||
<< "Part_Offset"
|
||||
<< "Part_Offset2D"
|
||||
<< "Part_Thickness"
|
||||
@@ -191,9 +191,12 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
|
||||
<< "Part_Mirror"
|
||||
<< "Part_Fillet"
|
||||
<< "Part_Chamfer"
|
||||
<< "Part_MakeFace"
|
||||
<< "Part_RuledSurface"
|
||||
<< "Part_Loft"
|
||||
<< "Part_Sweep"
|
||||
<< "Part_Section"
|
||||
<< "Part_CrossSections"
|
||||
<< "Part_CompOffset"
|
||||
<< "Part_Thickness"
|
||||
<< "Part_ProjectionOnSurface"
|
||||
@@ -209,9 +212,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
|
||||
<< "Part_CompJoinFeatures"
|
||||
<< "Part_CompSplitFeatures"
|
||||
<< "Part_CheckGeometry"
|
||||
<< "Part_Defeaturing"
|
||||
<< "Part_Section"
|
||||
<< "Part_CrossSections";
|
||||
<< "Part_Defeaturing";
|
||||
|
||||
Gui::ToolBarItem* measure = new Gui::ToolBarItem(root);
|
||||
measure->setCommand("Measure");
|
||||
|
||||
@@ -111,6 +111,7 @@ App::DocumentObjectExecReturn *Helix::execute(void)
|
||||
return new App::DocumentObjectExecReturn("Error: Pitch too small");
|
||||
if (Height.getValue() < Precision::Confusion())
|
||||
return new App::DocumentObjectExecReturn("Error: height too small!");
|
||||
Turns.setValue(Height.getValue()/Pitch.getValue());
|
||||
break;
|
||||
case 1: // pitch - turns
|
||||
if (Pitch.getValue() < Precision::Confusion())
|
||||
|
||||
@@ -55,7 +55,7 @@ using namespace Gui;
|
||||
|
||||
/* TRANSLATOR PartDesignGui::TaskLoftParameters */
|
||||
|
||||
TaskLoftParameters::TaskLoftParameters(ViewProviderLoft *LoftView,bool /*newObj*/, QWidget *parent)
|
||||
TaskLoftParameters::TaskLoftParameters(ViewProviderLoft *LoftView, bool /*newObj*/, QWidget *parent)
|
||||
: TaskSketchBasedParameters(LoftView, parent, "PartDesign_AdditiveLoft", tr("Loft parameters"))
|
||||
, ui(new Ui_TaskLoftParameters)
|
||||
{
|
||||
@@ -69,7 +69,7 @@ TaskLoftParameters::TaskLoftParameters(ViewProviderLoft *LoftView,bool /*newObj*
|
||||
connect(ui->buttonRefAdd, SIGNAL(toggled(bool)),
|
||||
this, SLOT(onRefButtonAdd(bool)));
|
||||
connect(ui->buttonRefRemove, SIGNAL(toggled(bool)),
|
||||
this, SLOT(onRefButtonRemvove(bool)));
|
||||
this, SLOT(onRefButtonRemove(bool)));
|
||||
connect(ui->checkBoxRuled, SIGNAL(toggled(bool)),
|
||||
this, SLOT(onRuled(bool)));
|
||||
connect(ui->checkBoxClosed, SIGNAL(toggled(bool)),
|
||||
@@ -121,24 +121,23 @@ TaskLoftParameters::TaskLoftParameters(ViewProviderLoft *LoftView,bool /*newObj*
|
||||
ui->checkBoxRuled->setChecked(loft->Ruled.getValue());
|
||||
ui->checkBoxClosed->setChecked(loft->Closed.getValue());
|
||||
|
||||
if (!loft->Sections.getValues().empty()) {
|
||||
LoftView->makeTemporaryVisible(true);
|
||||
}
|
||||
|
||||
// activate and de-activate dialog elements as appropriate
|
||||
for (QWidget* child : proxy->findChildren<QWidget*>())
|
||||
child->blockSignals(false);
|
||||
|
||||
updateUI(0);
|
||||
updateUI();
|
||||
}
|
||||
|
||||
TaskLoftParameters::~TaskLoftParameters()
|
||||
{
|
||||
}
|
||||
|
||||
void TaskLoftParameters::updateUI(int index)
|
||||
void TaskLoftParameters::updateUI()
|
||||
{
|
||||
Q_UNUSED(index);
|
||||
// we must assure the changed loft is kept visible on section changes,
|
||||
// see https://forum.freecadweb.org/viewtopic.php?f=3&t=63252
|
||||
PartDesign::Loft* loft = static_cast<PartDesign::Loft*>(vp->getObject());
|
||||
vp->makeTemporaryVisible(!loft->Sections.getValues().empty());
|
||||
}
|
||||
|
||||
void TaskLoftParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
|
||||
@@ -173,6 +172,7 @@ void TaskLoftParameters::onSelectionChanged(const Gui::SelectionChanges& msg)
|
||||
|
||||
clearButtons();
|
||||
exitSelectionMode();
|
||||
updateUI();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,6 +256,7 @@ void TaskLoftParameters::onDeleteSection()
|
||||
|
||||
//static_cast<ViewProviderLoft*>(vp)->highlightReferences(false, true);
|
||||
recomputeFeature();
|
||||
updateUI();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -279,6 +280,7 @@ void TaskLoftParameters::indexesMoved()
|
||||
|
||||
loft->Sections.setValues(originals);
|
||||
recomputeFeature();
|
||||
updateUI();
|
||||
}
|
||||
|
||||
void TaskLoftParameters::clearButtons() {
|
||||
@@ -324,7 +326,7 @@ void TaskLoftParameters::onRefButtonAdd(bool checked) {
|
||||
}
|
||||
}
|
||||
|
||||
void TaskLoftParameters::onRefButtonRemvove(bool checked) {
|
||||
void TaskLoftParameters::onRefButtonRemove(bool checked) {
|
||||
|
||||
if (checked) {
|
||||
Gui::Selection().clearSelection();
|
||||
@@ -359,7 +361,7 @@ bool TaskDlgLoftParameters::accept()
|
||||
// TODO Fill this with commands (2015-09-11, Fat-Zer)
|
||||
PartDesign::Loft* pcLoft = static_cast<PartDesign::Loft*>(vp->getObject());
|
||||
|
||||
for(App::DocumentObject* obj : pcLoft->Sections.getValues()) {
|
||||
for (App::DocumentObject* obj : pcLoft->Sections.getValues()) {
|
||||
FCMD_OBJ_HIDE(obj);
|
||||
}
|
||||
|
||||
|
||||
@@ -50,13 +50,13 @@ class TaskLoftParameters : public TaskSketchBasedParameters
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TaskLoftParameters(ViewProviderLoft *LoftView,bool newObj=false,QWidget *parent = 0);
|
||||
TaskLoftParameters(ViewProviderLoft *LoftView, bool newObj=false, QWidget *parent = 0);
|
||||
~TaskLoftParameters();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onProfileButton(bool);
|
||||
void onRefButtonAdd(bool);
|
||||
void onRefButtonRemvove(bool);
|
||||
void onRefButtonRemove(bool);
|
||||
void onClosed(bool);
|
||||
void onRuled(bool);
|
||||
void onDeleteSection();
|
||||
@@ -67,7 +67,7 @@ protected:
|
||||
|
||||
private:
|
||||
void onSelectionChanged(const Gui::SelectionChanges& msg);
|
||||
void updateUI(int index);
|
||||
void updateUI();
|
||||
bool referenceSelected(const Gui::SelectionChanges& msg) const;
|
||||
void removeFromListWidget(QListWidget*w, QString name);
|
||||
void clearButtons();
|
||||
|
||||
@@ -229,7 +229,8 @@ void TaskMultiTransformParameters::closeSubTask()
|
||||
|
||||
void TaskMultiTransformParameters::onTransformDelete()
|
||||
{
|
||||
if (editHint) return; // Can't delete the hint...
|
||||
if (editHint)
|
||||
return; // Can't delete the hint...
|
||||
int row = ui->listTransformFeatures->currentIndex().row();
|
||||
PartDesign::MultiTransform* pcMultiTransform = static_cast<PartDesign::MultiTransform*>(TransformedView->getObject());
|
||||
std::vector<App::DocumentObject*> transformFeatures = pcMultiTransform->Transformations.getValues();
|
||||
@@ -254,7 +255,8 @@ void TaskMultiTransformParameters::onTransformDelete()
|
||||
|
||||
void TaskMultiTransformParameters::onTransformEdit()
|
||||
{
|
||||
if (editHint) return; // Can't edit the hint...
|
||||
if (editHint)
|
||||
return; // Can't edit the hint...
|
||||
closeSubTask(); // For example if user is editing one subTask and then double-clicks on another without OK'ing first
|
||||
ui->listTransformFeatures->currentItem()->setSelected(true);
|
||||
int row = ui->listTransformFeatures->currentIndex().row();
|
||||
@@ -288,17 +290,23 @@ void TaskMultiTransformParameters::onTransformAddMirrored()
|
||||
closeSubTask();
|
||||
std::string newFeatName = TransformedView->getObject()->getDocument()->getUniqueObjectName("Mirrored");
|
||||
auto pcActiveBody = PartDesignGui::getBody(false);
|
||||
if(!pcActiveBody) return;
|
||||
if (!pcActiveBody)
|
||||
return;
|
||||
|
||||
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Mirrored"));
|
||||
FCMD_OBJ_CMD(pcActiveBody,"newObject('PartDesign::Mirrored','"<<newFeatName<<"')");
|
||||
FCMD_OBJ_CMD(pcActiveBody, "newObject('PartDesign::Mirrored','"<<newFeatName<<"')");
|
||||
auto Feat = pcActiveBody->getDocument()->getObject(newFeatName.c_str());
|
||||
if (!Feat)
|
||||
return;
|
||||
//Gui::Command::updateActive();
|
||||
App::DocumentObject* sketch = getSketchObject();
|
||||
if (sketch)
|
||||
FCMD_OBJ_CMD(Feat,"MirrorPlane = ("<<Gui::Command::getObjectCmd(sketch)<<",['V_Axis'])");
|
||||
FCMD_OBJ_CMD(Feat, "MirrorPlane = ("<<Gui::Command::getObjectCmd(sketch)<<",['V_Axis'])");
|
||||
|
||||
finishAdd(newFeatName);
|
||||
// show the new view when no error
|
||||
if (!Feat->isError())
|
||||
TransformedView->getObject()->Visibility.setValue(true);
|
||||
}
|
||||
|
||||
void TaskMultiTransformParameters::onTransformAddLinearPattern()
|
||||
@@ -308,29 +316,35 @@ void TaskMultiTransformParameters::onTransformAddLinearPattern()
|
||||
closeSubTask();
|
||||
std::string newFeatName = TransformedView->getObject()->getDocument()->getUniqueObjectName("LinearPattern");
|
||||
auto pcActiveBody = PartDesignGui::getBody(false);
|
||||
if(!pcActiveBody) return;
|
||||
if (!pcActiveBody)
|
||||
return;
|
||||
|
||||
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Make LinearPattern"));
|
||||
FCMD_OBJ_CMD(pcActiveBody,"newObject('PartDesign::LinearPattern','"<<newFeatName<<"')");
|
||||
FCMD_OBJ_CMD(pcActiveBody, "newObject('PartDesign::LinearPattern','"<<newFeatName<<"')");
|
||||
auto Feat = pcActiveBody->getDocument()->getObject(newFeatName.c_str());
|
||||
if (!Feat)
|
||||
return;
|
||||
//Gui::Command::updateActive();
|
||||
App::DocumentObject* sketch = getSketchObject();
|
||||
if (sketch) {
|
||||
FCMD_OBJ_CMD(Feat,"Direction = ("<<Gui::Command::getObjectCmd(sketch)<<",['H_Axis'])");
|
||||
FCMD_OBJ_CMD(Feat, "Direction = ("<<Gui::Command::getObjectCmd(sketch)<<",['H_Axis'])");
|
||||
}
|
||||
else {
|
||||
// set Direction value before filling up the combo box to avoid creating an empty item
|
||||
// inside updateUI()
|
||||
PartDesign::Body* body = static_cast<PartDesign::Body*>(Part::BodyBase::findBodyOf(getObject()));
|
||||
if (body) {
|
||||
FCMD_OBJ_CMD(Feat,"Direction = ("<<Gui::Command::getObjectCmd(body->getOrigin()->getX())<<",[''])");
|
||||
FCMD_OBJ_CMD(Feat, "Direction = ("<<Gui::Command::getObjectCmd(body->getOrigin()->getX())<<",[''])");
|
||||
}
|
||||
}
|
||||
|
||||
FCMD_OBJ_CMD(Feat,"Length = 100");
|
||||
FCMD_OBJ_CMD(Feat,"Occurrences = 2");
|
||||
FCMD_OBJ_CMD(Feat, "Length = 100");
|
||||
FCMD_OBJ_CMD(Feat, "Occurrences = 2");
|
||||
|
||||
finishAdd(newFeatName);
|
||||
// show the new view when no error
|
||||
if (!Feat->isError())
|
||||
TransformedView->getObject()->Visibility.setValue(true);
|
||||
}
|
||||
|
||||
void TaskMultiTransformParameters::onTransformAddPolarPattern()
|
||||
@@ -338,19 +352,25 @@ void TaskMultiTransformParameters::onTransformAddPolarPattern()
|
||||
closeSubTask();
|
||||
std::string newFeatName = TransformedView->getObject()->getDocument()->getUniqueObjectName("PolarPattern");
|
||||
auto pcActiveBody = PartDesignGui::getBody(false);
|
||||
if(!pcActiveBody) return;
|
||||
if (!pcActiveBody)
|
||||
return;
|
||||
|
||||
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "PolarPattern"));
|
||||
FCMD_OBJ_CMD(pcActiveBody,"newObject('PartDesign::PolarPattern','"<<newFeatName<<"')");
|
||||
FCMD_OBJ_CMD(pcActiveBody, "newObject('PartDesign::PolarPattern','"<<newFeatName<<"')");
|
||||
auto Feat = pcActiveBody->getDocument()->getObject(newFeatName.c_str());
|
||||
if (!Feat)
|
||||
return;
|
||||
//Gui::Command::updateActive();
|
||||
App::DocumentObject* sketch = getSketchObject();
|
||||
if (sketch)
|
||||
FCMD_OBJ_CMD(Feat, "Axis = ("<<Gui::Command::getObjectCmd(sketch)<<",['N_Axis'])");
|
||||
FCMD_OBJ_CMD(Feat,"Angle = 360");
|
||||
FCMD_OBJ_CMD(Feat,"Occurrences = 2");
|
||||
FCMD_OBJ_CMD(Feat, "Angle = 360");
|
||||
FCMD_OBJ_CMD(Feat, "Occurrences = 2");
|
||||
|
||||
finishAdd(newFeatName);
|
||||
// show the new view when no error
|
||||
if (!Feat->isError())
|
||||
TransformedView->getObject()->Visibility.setValue(true);
|
||||
}
|
||||
|
||||
void TaskMultiTransformParameters::onTransformAddScaled()
|
||||
@@ -358,16 +378,22 @@ void TaskMultiTransformParameters::onTransformAddScaled()
|
||||
closeSubTask();
|
||||
std::string newFeatName = TransformedView->getObject()->getDocument()->getUniqueObjectName("Scaled");
|
||||
auto pcActiveBody = PartDesignGui::getBody(false);
|
||||
if(!pcActiveBody) return;
|
||||
if (!pcActiveBody)
|
||||
return;
|
||||
|
||||
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Scaled"));
|
||||
FCMD_OBJ_CMD(pcActiveBody,"newObject('PartDesign::Scaled','"<<newFeatName<<"')");
|
||||
FCMD_OBJ_CMD(pcActiveBody, "newObject('PartDesign::Scaled','"<<newFeatName<<"')");
|
||||
auto Feat = pcActiveBody->getDocument()->getObject(newFeatName.c_str());
|
||||
if (!Feat)
|
||||
return;
|
||||
//Gui::Command::updateActive();
|
||||
FCMD_OBJ_CMD(Feat,"Factor = 2");
|
||||
FCMD_OBJ_CMD(Feat,"Occurrences = 2");
|
||||
FCMD_OBJ_CMD(Feat, "Factor = 2");
|
||||
FCMD_OBJ_CMD(Feat, "Occurrences = 2");
|
||||
|
||||
finishAdd(newFeatName);
|
||||
// show the new view when no error
|
||||
if (!Feat->isError())
|
||||
TransformedView->getObject()->Visibility.setValue(true);
|
||||
}
|
||||
|
||||
void TaskMultiTransformParameters::finishAdd(std::string &newFeatName)
|
||||
|
||||
@@ -94,6 +94,7 @@ TaskPipeParameters::TaskPipeParameters(ViewProviderPipe *PipeView, bool /*newObj
|
||||
// Create context menu
|
||||
QAction* remove = new QAction(tr("Remove"), this);
|
||||
remove->setShortcut(QKeySequence::Delete);
|
||||
remove->setShortcutContext(Qt::WidgetShortcut);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||
// display shortcut behind the context menu entry
|
||||
remove->setShortcutVisibleInContextMenu(true);
|
||||
@@ -582,6 +583,7 @@ TaskPipeOrientation::TaskPipeOrientation(ViewProviderPipe* PipeView, bool /*newO
|
||||
// Create context menu
|
||||
QAction* remove = new QAction(tr("Remove"), this);
|
||||
remove->setShortcut(QKeySequence::Delete);
|
||||
remove->setShortcutContext(Qt::WidgetShortcut);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||
// display shortcut behind the context menu entry
|
||||
remove->setShortcutVisibleInContextMenu(true);
|
||||
@@ -897,6 +899,7 @@ TaskPipeScaling::TaskPipeScaling(ViewProviderPipe* PipeView, bool /*newObj*/, QW
|
||||
// Create context menu
|
||||
QAction* remove = new QAction(tr("Remove"), this);
|
||||
remove->setShortcut(QKeySequence::Delete);
|
||||
remove->setShortcutContext(Qt::WidgetShortcut);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
|
||||
// display shortcut behind the context menu entry
|
||||
remove->setShortcutVisibleInContextMenu(true);
|
||||
|
||||
@@ -264,6 +264,7 @@ bool TaskDlgSketchBasedParameters::accept() {
|
||||
bool TaskDlgSketchBasedParameters::reject()
|
||||
{
|
||||
PartDesign::ProfileBased* pcSketchBased = static_cast<PartDesign::ProfileBased*>(vp->getObject());
|
||||
App::DocumentObjectWeakPtrT weakptr(pcSketchBased);
|
||||
// get the Sketch
|
||||
Sketcher::SketchObject *pcSketch = static_cast<Sketcher::SketchObject*>(pcSketchBased->Profile.getValue());
|
||||
bool rv;
|
||||
@@ -273,7 +274,7 @@ bool TaskDlgSketchBasedParameters::reject()
|
||||
|
||||
// if abort command deleted the object the sketch is visible again.
|
||||
// The previous one feature already should be made visible
|
||||
if (!Gui::Application::Instance->getViewProvider(pcSketchBased)) {
|
||||
if (weakptr.expired()) {
|
||||
// Make the sketch visible
|
||||
if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch))
|
||||
Gui::Application::Instance->getViewProvider(pcSketch)->show();
|
||||
|
||||
@@ -267,7 +267,7 @@ void ViewProviderAddSub::updateAddSubShapeIndicator() {
|
||||
|
||||
void ViewProviderAddSub::updateData(const App::Property* p) {
|
||||
|
||||
if(strcmp(p->getName(), "AddSubShape")==0)
|
||||
if(p->getName() && strcmp(p->getName(), "AddSubShape")==0)
|
||||
updateAddSubShapeIndicator();
|
||||
|
||||
PartDesignGui::ViewProvider::updateData(p);
|
||||
|
||||
@@ -68,10 +68,10 @@ def updateInputField(obj, prop, widget, onBeforeChange=None):
|
||||
isDiff = True
|
||||
break
|
||||
if noExpr:
|
||||
widget.setProperty('readonly', False)
|
||||
widget.setReadOnly(False)
|
||||
widget.setStyleSheet("color: black")
|
||||
else:
|
||||
widget.setProperty('readonly', True)
|
||||
widget.setReadOnly(True)
|
||||
widget.setStyleSheet("color: gray")
|
||||
widget.update()
|
||||
|
||||
@@ -100,6 +100,7 @@ class QuantitySpinBox:
|
||||
self.widget = widget
|
||||
self.onBeforeChange = onBeforeChange
|
||||
self.prop = None
|
||||
self.obj = obj
|
||||
self.attachTo(obj, prop)
|
||||
|
||||
def attachTo(self, obj, prop = None):
|
||||
@@ -139,9 +140,14 @@ class QuantitySpinBox:
|
||||
If no value is provided the value of the bound property is used.
|
||||
quantity can be of type Quantity or Float.'''
|
||||
PathLog.track(self.prop, self.valid)
|
||||
|
||||
if self.valid:
|
||||
expr = self._hasExpression()
|
||||
if quantity is None:
|
||||
quantity = PathUtil.getProperty(self.obj, self.prop)
|
||||
if expr:
|
||||
quantity = FreeCAD.Units.Quantity(self.obj.evalExpression(expr))
|
||||
else:
|
||||
quantity = PathUtil.getProperty(self.obj, self.prop)
|
||||
value = quantity.Value if hasattr(quantity, 'Value') else quantity
|
||||
self.widget.setProperty('rawValue', value)
|
||||
|
||||
@@ -151,3 +157,9 @@ class QuantitySpinBox:
|
||||
if self.valid:
|
||||
return updateInputField(self.obj, self.prop, self.widget, self.onBeforeChange)
|
||||
return None
|
||||
|
||||
def _hasExpression(self):
|
||||
for (prop, exp) in self.obj.ExpressionEngine:
|
||||
if prop == self.prop:
|
||||
return exp
|
||||
return None
|
||||
|
||||
@@ -171,7 +171,7 @@ class ObjectJob:
|
||||
obj.Stock.ViewObject.Visibility = False
|
||||
|
||||
def setupSetupSheet(self, obj):
|
||||
if not hasattr(obj, 'SetupSheet'):
|
||||
if not getattr(obj, 'SetupSheet', None):
|
||||
obj.addProperty('App::PropertyLink', 'SetupSheet', 'Base', QtCore.QT_TRANSLATE_NOOP('PathJob', 'SetupSheet holding the settings for this job'))
|
||||
obj.SetupSheet = PathSetupSheet.Create()
|
||||
if obj.SetupSheet.ViewObject:
|
||||
@@ -223,53 +223,58 @@ class ObjectJob:
|
||||
PathLog.track(obj.Label, arg2)
|
||||
doc = obj.Document
|
||||
|
||||
# the first to tear down are the ops, they depend on other resources
|
||||
PathLog.debug('taking down ops: %s' % [o.Name for o in self.allOperations()])
|
||||
while obj.Operations.Group:
|
||||
op = obj.Operations.Group[0]
|
||||
if not op.ViewObject or not hasattr(op.ViewObject.Proxy, 'onDelete') or op.ViewObject.Proxy.onDelete(op.ViewObject, ()):
|
||||
PathUtil.clearExpressionEngine(op)
|
||||
doc.removeObject(op.Name)
|
||||
obj.Operations.Group = []
|
||||
doc.removeObject(obj.Operations.Name)
|
||||
obj.Operations = None
|
||||
if getattr(obj, 'Operations', None):
|
||||
# the first to tear down are the ops, they depend on other resources
|
||||
PathLog.debug('taking down ops: %s' % [o.Name for o in self.allOperations()])
|
||||
while obj.Operations.Group:
|
||||
op = obj.Operations.Group[0]
|
||||
if not op.ViewObject or not hasattr(op.ViewObject.Proxy, 'onDelete') or op.ViewObject.Proxy.onDelete(op.ViewObject, ()):
|
||||
PathUtil.clearExpressionEngine(op)
|
||||
doc.removeObject(op.Name)
|
||||
obj.Operations.Group = []
|
||||
doc.removeObject(obj.Operations.Name)
|
||||
obj.Operations = None
|
||||
|
||||
# stock could depend on Model, so delete it first
|
||||
if obj.Stock:
|
||||
if getattr(obj, 'Stock', None):
|
||||
PathLog.debug('taking down stock')
|
||||
PathUtil.clearExpressionEngine(obj.Stock)
|
||||
doc.removeObject(obj.Stock.Name)
|
||||
obj.Stock = None
|
||||
|
||||
# base doesn't depend on anything inside job
|
||||
for base in obj.Model.Group:
|
||||
PathLog.debug("taking down base %s" % base.Label)
|
||||
self.removeBase(obj, base, False)
|
||||
obj.Model.Group = []
|
||||
doc.removeObject(obj.Model.Name)
|
||||
obj.Model = None
|
||||
if getattr(obj, 'Model', None):
|
||||
for base in obj.Model.Group:
|
||||
PathLog.debug("taking down base %s" % base.Label)
|
||||
self.removeBase(obj, base, False)
|
||||
obj.Model.Group = []
|
||||
doc.removeObject(obj.Model.Name)
|
||||
obj.Model = None
|
||||
|
||||
# Tool controllers might refer to either legacy tool or toolbit
|
||||
PathLog.debug('taking down tool controller')
|
||||
for tc in obj.Tools.Group:
|
||||
if hasattr(tc.Tool, "Proxy"):
|
||||
PathUtil.clearExpressionEngine(tc.Tool)
|
||||
doc.removeObject(tc.Tool.Name)
|
||||
PathUtil.clearExpressionEngine(tc)
|
||||
tc.Proxy.onDelete(tc)
|
||||
doc.removeObject(tc.Name)
|
||||
obj.Tools.Group = []
|
||||
doc.removeObject(obj.Tools.Name)
|
||||
obj.Tools = None
|
||||
if getattr(obj, 'Tools', None):
|
||||
PathLog.debug('taking down tool controller')
|
||||
for tc in obj.Tools.Group:
|
||||
if hasattr(tc.Tool, "Proxy"):
|
||||
PathUtil.clearExpressionEngine(tc.Tool)
|
||||
doc.removeObject(tc.Tool.Name)
|
||||
PathUtil.clearExpressionEngine(tc)
|
||||
tc.Proxy.onDelete(tc)
|
||||
doc.removeObject(tc.Name)
|
||||
obj.Tools.Group = []
|
||||
doc.removeObject(obj.Tools.Name)
|
||||
obj.Tools = None
|
||||
|
||||
# SetupSheet
|
||||
PathUtil.clearExpressionEngine(obj.SetupSheet)
|
||||
doc.removeObject(obj.SetupSheet.Name)
|
||||
obj.SetupSheet = None
|
||||
if getattr(obj, 'SetupSheet', None):
|
||||
PathUtil.clearExpressionEngine(obj.SetupSheet)
|
||||
doc.removeObject(obj.SetupSheet.Name)
|
||||
obj.SetupSheet = None
|
||||
|
||||
return True
|
||||
|
||||
def fixupOperations(self, obj):
|
||||
if obj.Operations.ViewObject:
|
||||
if getattr(obj.Operations, 'ViewObject', None):
|
||||
try:
|
||||
obj.Operations.ViewObject.DisplayMode
|
||||
except Exception: # pylint: disable=broad-except
|
||||
@@ -296,6 +301,18 @@ class ObjectJob:
|
||||
obj.addProperty("App::PropertyString", "CycleTime", "Path", QtCore.QT_TRANSLATE_NOOP("PathOp", "Operations Cycle Time Estimation"))
|
||||
obj.setEditorMode('CycleTime', 1) # read-only
|
||||
|
||||
if not hasattr(obj, "Fixtures"):
|
||||
obj.addProperty("App::PropertyStringList", "Fixtures", "WCS", QtCore.QT_TRANSLATE_NOOP("PathJob", "The Work Coordinate Systems for the Job"))
|
||||
obj.Fixtures = ['G54']
|
||||
|
||||
if not hasattr(obj, "OrderOutputBy"):
|
||||
obj.addProperty("App::PropertyEnumeration", "OrderOutputBy", "WCS", QtCore.QT_TRANSLATE_NOOP("PathJob", "If multiple WCS, order the output this way"))
|
||||
obj.OrderOutputBy = ['Fixture', 'Tool', 'Operation']
|
||||
|
||||
if not hasattr(obj, "SplitOutput"):
|
||||
obj.addProperty("App::PropertyBool", "SplitOutput", "Output", QtCore.QT_TRANSLATE_NOOP("PathJob", "Split output into multiple gcode files"))
|
||||
obj.SplitOutput = False
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
if prop == "PostProcessor" and obj.PostProcessor:
|
||||
processor = PostProcessor.load(obj.PostProcessor)
|
||||
@@ -397,7 +414,7 @@ class ObjectJob:
|
||||
return None
|
||||
|
||||
def execute(self, obj):
|
||||
if hasattr(obj, 'Operations'):
|
||||
if getattr(obj, 'Operations', None):
|
||||
obj.Path = obj.Operations.Path
|
||||
self.getCycleTime()
|
||||
|
||||
@@ -445,6 +462,11 @@ class ObjectJob:
|
||||
self.obj.Operations.Group = group
|
||||
op.Path.Center = self.obj.Operations.Path.Center
|
||||
|
||||
def nextToolNumber(self):
|
||||
# returns the next available toolnumber in the job
|
||||
group = self.obj.Tools.Group
|
||||
return sorted([t.ToolNumber for t in group])[-1] + 1
|
||||
|
||||
def addToolController(self, tc):
|
||||
group = self.obj.Tools.Group
|
||||
PathLog.debug("addToolController(%s): %s" % (tc.Label, [t.Label for t in group]))
|
||||
@@ -467,8 +489,11 @@ class ObjectJob:
|
||||
ops.append(op)
|
||||
for sub in op.Group:
|
||||
collectBaseOps(sub)
|
||||
for op in self.obj.Operations.Group:
|
||||
collectBaseOps(op)
|
||||
|
||||
if getattr(self.obj, 'Operations', None) and getattr(self.obj.Operations, 'Group', None):
|
||||
for op in self.obj.Operations.Group:
|
||||
collectBaseOps(op)
|
||||
|
||||
return ops
|
||||
|
||||
def setCenterOfRotation(self, center):
|
||||
|
||||
@@ -213,7 +213,8 @@ class JobCreate:
|
||||
def setupTemplate(self):
|
||||
templateFiles = []
|
||||
for path in PathPreferences.searchPaths():
|
||||
templateFiles.extend(self.templateFilesIn(path))
|
||||
cleanPaths = [f.replace("\\", "/") for f in self.templateFilesIn(path)] # Standardize slashes used accross os platforms
|
||||
templateFiles.extend(cleanPaths)
|
||||
|
||||
template = {}
|
||||
for tFile in templateFiles:
|
||||
|
||||
@@ -27,11 +27,11 @@ import math
|
||||
import traceback
|
||||
from pivy import coin
|
||||
from PySide import QtCore, QtGui
|
||||
import json
|
||||
|
||||
import FreeCAD
|
||||
import FreeCADGui
|
||||
|
||||
import PathGui as PGui # ensure Path/Gui/Resources are loaded
|
||||
import PathScripts.PathJob as PathJob
|
||||
import PathScripts.PathJobCmd as PathJobCmd
|
||||
import PathScripts.PathJobDlg as PathJobDlg
|
||||
@@ -59,17 +59,11 @@ def translate(context, text, disambig=None):
|
||||
return QtCore.QCoreApplication.translate(context, text, disambig)
|
||||
|
||||
|
||||
LOGLEVEL = False
|
||||
|
||||
if LOGLEVEL:
|
||||
PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) # lgtm [py/unreachable-statement]
|
||||
PathLog.trackModule(PathLog.thisModule()) # lgtm [py/unreachable-statement]
|
||||
else:
|
||||
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
|
||||
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
|
||||
# PathLog.trackModule(PathLog.thisModule())
|
||||
|
||||
|
||||
def _OpenCloseResourceEditor(obj, vobj, edit):
|
||||
# pylint: disable=unused-argument
|
||||
job = PathUtils.findParentJob(obj)
|
||||
if job and job.ViewObject and job.ViewObject.Proxy:
|
||||
if edit:
|
||||
@@ -171,7 +165,6 @@ class ViewProvider:
|
||||
return hasattr(self, 'deleteOnReject') and self.deleteOnReject
|
||||
|
||||
def setEdit(self, vobj=None, mode=0):
|
||||
# pylint: disable=unused-argument
|
||||
PathLog.track(mode)
|
||||
if 0 == mode:
|
||||
self.openTaskPanel()
|
||||
@@ -190,7 +183,6 @@ class ViewProvider:
|
||||
self.taskPanel = None
|
||||
|
||||
def unsetEdit(self, arg1, arg2):
|
||||
# pylint: disable=unused-argument
|
||||
if self.taskPanel:
|
||||
self.taskPanel.reject(False)
|
||||
|
||||
@@ -204,7 +196,6 @@ class ViewProvider:
|
||||
return self.openTaskPanel()
|
||||
|
||||
def uneditObject(self, obj=None):
|
||||
# pylint: disable=unused-argument
|
||||
self.unsetEdit(None, None)
|
||||
|
||||
def getIcon(self):
|
||||
@@ -250,7 +241,6 @@ class ViewProvider:
|
||||
base.ViewObject.Visibility = True
|
||||
|
||||
def forgetBaseVisibility(self, obj, base):
|
||||
# pylint: disable=unused-argument
|
||||
if self.baseVisibility.get(base.Name):
|
||||
visibility = self.baseVisibility[base.Name]
|
||||
visibility[0].ViewObject.Visibility = visibility[1]
|
||||
@@ -274,7 +264,6 @@ class ViewProvider:
|
||||
obj.Stock.ViewObject.Visibility = self.stockVisibility
|
||||
|
||||
def setupContextMenu(self, vobj, menu):
|
||||
# pylint: disable=unused-argument
|
||||
PathLog.track()
|
||||
for action in menu.actions():
|
||||
menu.removeAction(action)
|
||||
@@ -308,7 +297,7 @@ class StockEdit(object):
|
||||
widget.hide()
|
||||
if select:
|
||||
self.form.stock.setCurrentIndex(self.Index)
|
||||
editor = self.editorFrame() # pylint: disable=assignment-from-none
|
||||
editor = self.editorFrame()
|
||||
showHide(self.form.stockFromExisting, editor)
|
||||
showHide(self.form.stockFromBase, editor)
|
||||
showHide(self.form.stockCreateBox, editor)
|
||||
@@ -370,7 +359,7 @@ class StockFromBaseBoundBoxEdit(StockEdit):
|
||||
stock.ExtZneg = FreeCAD.Units.Quantity(self.form.stockExtZneg.text())
|
||||
if 'zpos' in fields:
|
||||
stock.ExtZpos = FreeCAD.Units.Quantity(self.form.stockExtZpos.text())
|
||||
except Exception: # pylint: disable=broad-except
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def getFields(self, obj, fields=None):
|
||||
@@ -411,7 +400,7 @@ class StockFromBaseBoundBoxEdit(StockEdit):
|
||||
self.form.stockExtYpos.textChanged.connect(self.checkYpos)
|
||||
self.form.stockExtZpos.textChanged.connect(self.checkZpos)
|
||||
if hasattr(self.form, 'linkStockAndModel'):
|
||||
self.form.linkStockAndModel.setChecked(True)
|
||||
self.form.linkStockAndModel.setChecked(False)
|
||||
|
||||
def checkXpos(self):
|
||||
self.trackXpos = self.form.stockExtXneg.text() == self.form.stockExtXpos.text()
|
||||
@@ -467,7 +456,7 @@ class StockCreateBoxEdit(StockEdit):
|
||||
obj.Stock.Height = FreeCAD.Units.Quantity(self.form.stockBoxHeight.text())
|
||||
else:
|
||||
PathLog.error(translate('PathJob', 'Stock not a box!'))
|
||||
except Exception: # pylint: disable=broad-except
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def setFields(self, obj):
|
||||
@@ -503,7 +492,7 @@ class StockCreateCylinderEdit(StockEdit):
|
||||
obj.Stock.Height = FreeCAD.Units.Quantity(self.form.stockCylinderHeight.text())
|
||||
else:
|
||||
PathLog.error(translate('PathJob', 'Stock not a cylinder!'))
|
||||
except Exception: # pylint: disable=broad-except
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def setFields(self, obj):
|
||||
@@ -531,7 +520,7 @@ class StockFromExistingEdit(StockEdit):
|
||||
stock = self.form.stockExisting.itemData(self.form.stockExisting.currentIndex())
|
||||
if not (hasattr(obj.Stock, 'Objects') and len(obj.Stock.Objects) == 1 and obj.Stock.Objects[0] == stock):
|
||||
if stock:
|
||||
stock = PathJob.createResourceClone(obj, stock, self.StockLabelPrefix , 'Stock')
|
||||
stock = PathJob.createResourceClone(obj, stock, self.StockLabelPrefix, 'Stock')
|
||||
stock.ViewObject.Visibility = True
|
||||
PathStock.SetupStockObject(stock, PathStock.StockType.Unknown)
|
||||
stock.Proxy.execute(stock)
|
||||
@@ -557,7 +546,7 @@ class StockFromExistingEdit(StockEdit):
|
||||
index = -1
|
||||
for i, solid in enumerate(self.candidates(obj)):
|
||||
self.form.stockExisting.addItem(solid.Label, solid)
|
||||
label="{}-{}".format(self.StockLabelPrefix, solid.Label)
|
||||
label = "{}-{}".format(self.StockLabelPrefix, solid.Label)
|
||||
|
||||
if label == stockName:
|
||||
index = i
|
||||
@@ -583,6 +572,7 @@ class TaskPanel:
|
||||
self.deleteOnReject = deleteOnReject
|
||||
self.form = FreeCADGui.PySideUic.loadUi(":/panels/PathEdit.ui")
|
||||
self.template = PathJobDlg.JobTemplateExport(self.obj, self.form.jobBox.widget(1))
|
||||
self.name = self.obj.Name
|
||||
|
||||
vUnit = FreeCAD.Units.Quantity(1, FreeCAD.Units.Velocity).getUserPreferred()[2]
|
||||
self.form.toolControllerList.horizontalHeaderItem(1).setText('#')
|
||||
@@ -634,12 +624,14 @@ class TaskPanel:
|
||||
self.setupGlobal.reject()
|
||||
self.setupOps.reject()
|
||||
FreeCAD.ActiveDocument.abortTransaction()
|
||||
if self.deleteOnReject:
|
||||
if self.deleteOnReject and FreeCAD.ActiveDocument.getObject(self.name):
|
||||
PathLog.info("Uncreate Job")
|
||||
FreeCAD.ActiveDocument.openTransaction(translate("Path_Job", "Uncreate Job"))
|
||||
if self.obj.ViewObject.Proxy.onDelete(self.obj.ViewObject, None):
|
||||
FreeCAD.ActiveDocument.removeObject(self.obj.Name)
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
else:
|
||||
PathLog.track(self.name, self.deleteOnReject, FreeCAD.ActiveDocument.getObject(self.name))
|
||||
self.cleanup(resetEdit)
|
||||
return True
|
||||
|
||||
@@ -680,7 +672,7 @@ class TaskPanel:
|
||||
if self.form.wcslist.item(i).checkState() == QtCore.Qt.CheckState.Checked:
|
||||
flist.append(self.form.wcslist.item(i).text())
|
||||
self.obj.Fixtures = flist
|
||||
except Exception: # pylint: disable=broad-except
|
||||
except Exception:
|
||||
FreeCAD.Console.PrintWarning("The Job was created without fixture support. Please delete and recreate the job\r\n")
|
||||
|
||||
self.updateTooltips()
|
||||
@@ -872,13 +864,33 @@ class TaskPanel:
|
||||
self.toolControllerSelect()
|
||||
|
||||
def toolControllerAdd(self):
|
||||
# adding a TC from a toolbit directly.
|
||||
# Try to find a tool number from the currently selected lib. Otherwise
|
||||
# use next available number
|
||||
|
||||
if PathPreferences.toolsUseLegacyTools():
|
||||
PathToolLibraryEditor.CommandToolLibraryEdit().edit(self.obj, self.updateToolController)
|
||||
else:
|
||||
tools = PathToolBitGui.LoadTools()
|
||||
|
||||
curLib = PathPreferences.lastFileToolLibrary()
|
||||
|
||||
library = None
|
||||
if curLib is not None:
|
||||
with open(curLib) as fp:
|
||||
library = json.load(fp)
|
||||
|
||||
for tool in tools:
|
||||
tc = PathToolControllerGui.Create(name=tool.Label, tool=tool)
|
||||
toolNum = self.obj.Proxy.nextToolNumber()
|
||||
if library is not None:
|
||||
for toolBit in library['tools']:
|
||||
|
||||
if toolBit['path'] == tool.File:
|
||||
toolNum = toolBit['nr']
|
||||
|
||||
tc = PathToolControllerGui.Create(name=tool.Label, tool=tool, toolNumber=toolNum)
|
||||
self.obj.Proxy.addToolController(tc)
|
||||
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
self.updateToolController()
|
||||
|
||||
@@ -894,7 +906,7 @@ class TaskPanel:
|
||||
elif 'Number' == prop:
|
||||
try:
|
||||
tc.ToolNumber = int(item.text())
|
||||
except Exception: # pylint: disable=broad-except
|
||||
except Exception:
|
||||
pass
|
||||
item.setText("%d" % tc.ToolNumber)
|
||||
elif 'Spindle' == prop:
|
||||
@@ -906,7 +918,7 @@ class TaskPanel:
|
||||
speed = -speed
|
||||
tc.SpindleDir = rot
|
||||
tc.SpindleSpeed = speed
|
||||
except Exception: # pylint: disable=broad-except
|
||||
except Exception:
|
||||
pass
|
||||
item.setText("%s%g" % ('+' if tc.SpindleDir == 'Forward' else '-', tc.SpindleSpeed))
|
||||
elif 'HorizFeed' == prop or 'VertFeed' == prop:
|
||||
@@ -918,58 +930,69 @@ class TaskPanel:
|
||||
elif FreeCAD.Units.Unit() == val.Unit:
|
||||
val = FreeCAD.Units.Quantity(item.text() + vUnit)
|
||||
setattr(tc, prop, val)
|
||||
except Exception: # pylint: disable=broad-except
|
||||
except Exception:
|
||||
pass
|
||||
item.setText("%g" % getattr(tc, prop).getValueAs(vUnit))
|
||||
else:
|
||||
try:
|
||||
val = FreeCAD.Units.Quantity(item.text())
|
||||
setattr(tc, prop, val)
|
||||
except Exception: # pylint: disable=broad-except
|
||||
except Exception:
|
||||
pass
|
||||
item.setText("%g" % getattr(tc, prop).Value)
|
||||
|
||||
self.template.updateUI()
|
||||
|
||||
def modelSetAxis(self, axis):
|
||||
def alignSel(sel, n, flip=False):
|
||||
PathLog.debug("alignSel")
|
||||
PathLog.track(axis)
|
||||
|
||||
def alignSel(sel, normal, flip=False):
|
||||
PathLog.track("Vector(%.2f, %.2f, %.2f)" % (normal.x, normal.y, normal.z), flip)
|
||||
vector = axis
|
||||
if flip:
|
||||
vector = n.negative()
|
||||
r = axis.cross(n) # rotation axis
|
||||
a = DraftVecUtils.angle(n, vector, r) * 180 / math.pi
|
||||
vector = axis.negative()
|
||||
r = axis.cross(normal) # rotation axis
|
||||
a = DraftVecUtils.angle(normal, vector, r) * 180 / math.pi
|
||||
PathLog.debug("oh boy: (%.2f, %.2f, %.2f) -> %.2f" % (r.x, r.y, r.z, a))
|
||||
Draft.rotate(sel.Object, a, axis=r)
|
||||
|
||||
selObject = None
|
||||
selFeature = None
|
||||
for sel in FreeCADGui.Selection.getSelectionEx():
|
||||
selObject = sel.Object
|
||||
for feature in sel.SubElementNames:
|
||||
selFeature = feature
|
||||
sub = sel.Object.Shape.getElement(feature)
|
||||
if 'Face' == sub.ShapeType:
|
||||
n = sub.normalAt(0, 0).negative()
|
||||
if sub.Orientation == 'Reversed':
|
||||
n = FreeCAD.Vector() - n
|
||||
PathLog.debug("(%.2f, %.2f, %.2f) -> reversed (%s)" % (n.x, n.y, n.z, sub.Orientation))
|
||||
else:
|
||||
PathLog.debug("(%.2f, %.2f, %.2f) -> forward (%s)" % (n.x, n.y, n.z, sub.Orientation))
|
||||
with selectionEx() as selection:
|
||||
for sel in selection:
|
||||
selObject = sel.Object
|
||||
for feature in sel.SubElementNames:
|
||||
selFeature = feature
|
||||
PathLog.track(selObject.Label, feature)
|
||||
sub = sel.Object.Shape.getElement(feature)
|
||||
|
||||
if PathGeom.pointsCoincide(axis, n) or PathGeom.pointsCoincide(axis, FreeCAD.Vector() - n):
|
||||
alignSel(sel, n, True)
|
||||
else:
|
||||
alignSel(sel, n)
|
||||
if 'Face' == sub.ShapeType:
|
||||
normal = sub.normalAt(0, 0)
|
||||
if sub.Orientation == 'Reversed':
|
||||
normal = FreeCAD.Vector() - normal
|
||||
PathLog.debug("(%.2f, %.2f, %.2f) -> reversed (%s)" % (normal.x, normal.y, normal.z, sub.Orientation))
|
||||
else:
|
||||
PathLog.debug("(%.2f, %.2f, %.2f) -> forward (%s)" % (normal.x, normal.y, normal.z, sub.Orientation))
|
||||
|
||||
if PathGeom.pointsCoincide(axis, normal):
|
||||
alignSel(sel, normal, True)
|
||||
elif PathGeom.pointsCoincide(axis, FreeCAD.Vector() - normal):
|
||||
alignSel(sel, FreeCAD.Vector() - normal, True)
|
||||
else:
|
||||
alignSel(sel, normal)
|
||||
|
||||
elif 'Edge' == sub.ShapeType:
|
||||
normal = (sub.Vertexes[1].Point - sub.Vertexes[0].Point).normalize()
|
||||
if PathGeom.pointsCoincide(axis, normal) or PathGeom.pointsCoincide(axis, FreeCAD.Vector() - normal):
|
||||
# Don't really know the orientation of an edge, so let's just flip the object
|
||||
# and if the user doesn't like it they can flip again
|
||||
alignSel(sel, normal, True)
|
||||
else:
|
||||
alignSel(sel, normal)
|
||||
|
||||
if 'Edge' == sub.ShapeType:
|
||||
n = (sub.Vertexes[1].Point - sub.Vertexes[0].Point).normalize()
|
||||
if PathGeom.pointsCoincide(axis, n) or PathGeom.pointsCoincide(axis, FreeCAD.Vector() - n):
|
||||
# Don't really know the orientation of an edge, so let's just flip the object
|
||||
# and if the user doesn't like it they can flip again
|
||||
alignSel(sel, n, True)
|
||||
else:
|
||||
alignSel(sel, n)
|
||||
PathLog.track(sub.ShapeType)
|
||||
|
||||
if selObject and selFeature:
|
||||
FreeCADGui.Selection.clearSelection()
|
||||
FreeCADGui.Selection.addSelection(selObject, selFeature)
|
||||
@@ -980,10 +1003,13 @@ class TaskPanel:
|
||||
FreeCADGui.Selection.addSelection(sel.Object, sel.SubElementNames)
|
||||
|
||||
def modelSet0(self, axis):
|
||||
PathLog.track(axis)
|
||||
with selectionEx() as selection:
|
||||
for sel in selection:
|
||||
selObject = sel.Object
|
||||
PathLog.track(selObject.Label)
|
||||
for name in sel.SubElementNames:
|
||||
PathLog.track(selObject.Label, name)
|
||||
feature = selObject.Shape.getElement(name)
|
||||
bb = feature.BoundBox
|
||||
offset = FreeCAD.Vector(axis.x * bb.XMax, axis.y * bb.YMax, axis.z * bb.ZMax)
|
||||
@@ -1216,7 +1242,7 @@ class TaskPanel:
|
||||
|
||||
# first remove all obsolete base models
|
||||
for model, count in PathUtil.keyValueIter(obsolete):
|
||||
for i in range(count): # pylint: disable=unused-variable
|
||||
for i in range(count):
|
||||
# it seems natural to remove the last of all the base objects for a given model
|
||||
base = [b for b in obj.Model.Group if proxy.baseObject(obj, b) == model][-1]
|
||||
self.vproxy.forgetBaseVisibility(obj, base)
|
||||
@@ -1338,19 +1364,15 @@ class TaskPanel:
|
||||
|
||||
# SelectionObserver interface
|
||||
def addSelection(self, doc, obj, sub, pnt):
|
||||
# pylint: disable=unused-argument
|
||||
self.updateSelection()
|
||||
|
||||
def removeSelection(self, doc, obj, sub):
|
||||
# pylint: disable=unused-argument
|
||||
self.updateSelection()
|
||||
|
||||
def setSelection(self, doc):
|
||||
# pylint: disable=unused-argument
|
||||
self.updateSelection()
|
||||
|
||||
def clearSelection(self, doc):
|
||||
# pylint: disable=unused-argument
|
||||
self.updateSelection()
|
||||
|
||||
|
||||
@@ -1366,7 +1388,7 @@ def Create(base, template=None):
|
||||
obj.Document.recompute()
|
||||
obj.ViewObject.Proxy.editObject(obj.Stock)
|
||||
return obj
|
||||
except Exception as exc: # pylint: disable=broad-except
|
||||
except Exception as exc:
|
||||
PathLog.error(exc)
|
||||
traceback.print_exc()
|
||||
FreeCAD.ActiveDocument.abortTransaction()
|
||||
|
||||
@@ -195,16 +195,20 @@ class ObjectFace(PathPocketBase.ObjectPocket):
|
||||
import PathScripts.PathSurfaceSupport as PathSurfaceSupport
|
||||
baseShape = oneBase[0].Shape
|
||||
psZMin = planeshape.BoundBox.ZMin
|
||||
ofstShape = PathUtils.getOffsetArea(planeshape,
|
||||
self.tool.Diameter * 1.1,
|
||||
plane=planeshape)
|
||||
ofst = 0.0
|
||||
if obj.ClearEdges:
|
||||
ofst = self.tool.Diameter * 0.51
|
||||
ofstShape = PathUtils.getOffsetArea(planeshape, ofst, plane=planeshape)
|
||||
ofstShape.translate(FreeCAD.Vector(0.0, 0.0, psZMin - ofstShape.BoundBox.ZMin))
|
||||
|
||||
# Calculate custom depth params for removal shape envelope, with start and final depth buffers
|
||||
custDepthparams = self._customDepthParams(obj, obj.StartDepth.Value + 0.2, obj.FinalDepth.Value - 0.1) # only an envelope
|
||||
ofstShapeEnv = PathUtils.getEnvelope(partshape=ofstShape, depthparams=custDepthparams)
|
||||
env = ofstShapeEnv.cut(baseShape)
|
||||
env.translate(FreeCAD.Vector(0.0, 0.0, -0.000001)) # lower removal shape into buffer zone
|
||||
if obj.ExcludeRaisedAreas:
|
||||
env = ofstShapeEnv.cut(baseShape)
|
||||
env.translate(FreeCAD.Vector(0.0, 0.0, -0.00001)) # lower removal shape into buffer zone
|
||||
else:
|
||||
env = ofstShapeEnv
|
||||
|
||||
if holeShape:
|
||||
PathLog.debug("Processing holes and face ...")
|
||||
|
||||
@@ -1113,7 +1113,7 @@ class TaskPanel(object):
|
||||
def accept(self, resetEdit=True):
|
||||
'''accept() ... callback invoked when user presses the task panel OK button.'''
|
||||
self.preCleanup()
|
||||
if self.isDirty:
|
||||
if self.isDirty():
|
||||
self.panelGetFields()
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
self.cleanup(resetEdit)
|
||||
@@ -1207,7 +1207,18 @@ class TaskPanel(object):
|
||||
page.clearBase()
|
||||
page.addBaseGeometry(sel)
|
||||
|
||||
# Update properties based upon expressions in case expression value has changed
|
||||
for (prp, expr) in self.obj.ExpressionEngine:
|
||||
val = FreeCAD.Units.Quantity(self.obj.evalExpression(expr))
|
||||
value = val.Value if hasattr(val, 'Value') else val
|
||||
prop = getattr(self.obj, prp)
|
||||
if hasattr(prop, "Value"):
|
||||
prop.Value = value
|
||||
else:
|
||||
prop = value
|
||||
|
||||
self.panelSetFields()
|
||||
|
||||
for page in self.featurePages:
|
||||
page.pageRegisterSignalHandlers()
|
||||
|
||||
|
||||
@@ -391,6 +391,10 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
|
||||
self.horiz.append(face)
|
||||
self.exts.append(face)
|
||||
|
||||
# Place all self.horiz faces into same working plane
|
||||
for h in self.horiz:
|
||||
h.translate(FreeCAD.Vector(0.0, 0.0, 0.0 - h.BoundBox.ZMin))
|
||||
|
||||
# check all faces and see if they are touching/overlapping and combine those into a compound
|
||||
self.horizontal = [] # pylint: disable=attribute-defined-outside-init
|
||||
for shape in PathGeom.combineConnectedShapes(self.horiz):
|
||||
|
||||
@@ -158,7 +158,7 @@ class CommandPathPost:
|
||||
|
||||
if openDialog:
|
||||
foo = QtGui.QFileDialog.getSaveFileName(QtGui.QApplication.activeWindow(), "Output File", filename)
|
||||
if foo:
|
||||
if foo[0]:
|
||||
filename = foo[0]
|
||||
else:
|
||||
filename = None
|
||||
@@ -236,7 +236,7 @@ class CommandPathPost:
|
||||
elif hasattr(sel, "Path"):
|
||||
try:
|
||||
job = PathUtils.findParentJob(sel)
|
||||
except Exception: # pylint: disable=broad-except
|
||||
except Exception:
|
||||
job = None
|
||||
else:
|
||||
job = None
|
||||
@@ -261,22 +261,9 @@ class CommandPathPost:
|
||||
|
||||
PathLog.debug("about to postprocess job: {}".format(job.Name))
|
||||
|
||||
# Build up an ordered list of operations and tool changes.
|
||||
# Then post-the ordered list
|
||||
if hasattr(job, "Fixtures"):
|
||||
wcslist = job.Fixtures
|
||||
else:
|
||||
wcslist = ['G54']
|
||||
|
||||
if hasattr(job, "OrderOutputBy"):
|
||||
orderby = job.OrderOutputBy
|
||||
else:
|
||||
orderby = "Operation"
|
||||
|
||||
if hasattr(job, "SplitOutput"):
|
||||
split = job.SplitOutput
|
||||
else:
|
||||
split = False
|
||||
wcslist = job.Fixtures
|
||||
orderby = job.OrderOutputBy
|
||||
split = job.SplitOutput
|
||||
|
||||
postlist = []
|
||||
|
||||
@@ -301,7 +288,7 @@ class CommandPathPost:
|
||||
for obj in job.Operations.Group:
|
||||
tc = PathUtil.toolControllerForOp(obj)
|
||||
if tc is not None and PathUtil.opProperty(obj, 'Active'):
|
||||
if tc.ToolNumber != currTool:
|
||||
if tc.ToolNumber != currTool or split is True:
|
||||
sublist.append(tc)
|
||||
PathLog.debug("Appending TC: {}".format(tc.Name))
|
||||
currTool = tc.ToolNumber
|
||||
@@ -332,7 +319,7 @@ class CommandPathPost:
|
||||
for idx, obj in enumerate(job.Operations.Group):
|
||||
|
||||
# check if the operation is active
|
||||
active = PathUtil.opProperty(obj, 'Active')
|
||||
active = PathUtil.opProperty(obj, 'Active')
|
||||
|
||||
tc = PathUtil.toolControllerForOp(obj)
|
||||
if tc is None or tc.ToolNumber == currTool and active:
|
||||
@@ -380,17 +367,19 @@ class CommandPathPost:
|
||||
firstFixture = False
|
||||
tc = PathUtil.toolControllerForOp(obj)
|
||||
if tc is not None:
|
||||
if tc.ToolNumber != currTool:
|
||||
if job.SplitOutput or (tc.ToolNumber != currTool):
|
||||
sublist.append(tc)
|
||||
currTool = tc.ToolNumber
|
||||
sublist.append(obj)
|
||||
postlist.append(sublist)
|
||||
|
||||
fail = True
|
||||
rc = '' # pylint: disable=unused-variable
|
||||
rc = ''
|
||||
if split:
|
||||
for slist in postlist:
|
||||
(fail, rc, filename) = self.exportObjectsWith(slist, job)
|
||||
if fail:
|
||||
break
|
||||
else:
|
||||
finalpostlist = [item for slist in postlist for item in slist]
|
||||
(fail, rc, filename) = self.exportObjectsWith(finalpostlist, job)
|
||||
|
||||
@@ -448,7 +448,6 @@ class ObjectProfile(PathAreaOp.ObjectOp):
|
||||
else: # Try to build targets from the job models
|
||||
# No base geometry selected, so treating operation like a exterior contour operation
|
||||
self.opUpdateDepths(obj)
|
||||
obj.Side = 'Outside' # Force outside for whole model profile
|
||||
|
||||
if 1 == len(self.model) and hasattr(self.model[0], "Proxy"):
|
||||
if isinstance(self.model[0].Proxy, ArchPanel.PanelSheet): # process the sheet
|
||||
|
||||
@@ -22,11 +22,11 @@
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
'''
|
||||
"""
|
||||
This file has utilities for checking and catching common errors in FreeCAD
|
||||
Path projects. Ideally, the user could execute these utilities from an icon
|
||||
to make sure tools are selected and configured and defaults have been revised
|
||||
'''
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
from PySide import QtCore, QtGui
|
||||
@@ -40,6 +40,7 @@ from collections import Counter
|
||||
from datetime import datetime
|
||||
import os
|
||||
import webbrowser
|
||||
|
||||
# Qt translation handling
|
||||
|
||||
|
||||
@@ -47,13 +48,12 @@ def translate(context, text, disambig=None):
|
||||
return QtCore.QCoreApplication.translate(context, text, disambig)
|
||||
|
||||
|
||||
LOG_MODULE = 'PathSanity'
|
||||
LOG_MODULE = "PathSanity"
|
||||
# PathLog.setLevel(PathLog.Level.INFO, LOG_MODULE)
|
||||
# PathLog.trackModule('PathSanity')
|
||||
|
||||
|
||||
class CommandPathSanity:
|
||||
|
||||
def resolveOutputPath(self, job):
|
||||
if job.PostProcessorOutputFile != "":
|
||||
filepath = job.PostProcessorOutputFile
|
||||
@@ -62,48 +62,54 @@ class CommandPathSanity:
|
||||
else:
|
||||
filepath = PathPreferences.macroFilePath()
|
||||
|
||||
if '%D' in filepath:
|
||||
if "%D" in filepath:
|
||||
D = FreeCAD.ActiveDocument.FileName
|
||||
if D:
|
||||
D = os.path.dirname(D)
|
||||
# in case the document is in the current working directory
|
||||
if not D:
|
||||
D = '.'
|
||||
D = "."
|
||||
else:
|
||||
FreeCAD.Console.PrintError("Please save document in order to resolve output path!\n")
|
||||
FreeCAD.Console.PrintError(
|
||||
"Please save document in order to resolve output path!\n"
|
||||
)
|
||||
return None
|
||||
filepath = filepath.replace('%D', D)
|
||||
filepath = filepath.replace("%D", D)
|
||||
|
||||
if '%d' in filepath:
|
||||
if "%d" in filepath:
|
||||
d = FreeCAD.ActiveDocument.Label
|
||||
filepath = filepath.replace('%d', d)
|
||||
filepath = filepath.replace("%d", d)
|
||||
|
||||
if '%j' in filepath:
|
||||
if "%j" in filepath:
|
||||
j = job.Label
|
||||
filepath = filepath.replace('%j', j)
|
||||
filepath = filepath.replace("%j", j)
|
||||
|
||||
if '%M' in filepath:
|
||||
if "%M" in filepath:
|
||||
pref = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Macro")
|
||||
M = pref.GetString("MacroPath", FreeCAD.getUserAppDataDir())
|
||||
filepath = filepath.replace('%M', M)
|
||||
filepath = filepath.replace("%M", M)
|
||||
|
||||
PathLog.debug('filepath: {}'.format(filepath))
|
||||
PathLog.debug("filepath: {}".format(filepath))
|
||||
|
||||
# starting at the derived filename, iterate up until we have a valid
|
||||
# directory to write to
|
||||
while not os.path.isdir(filepath):
|
||||
filepath = os.path.dirname(filepath)
|
||||
|
||||
PathLog.debug('filepath: {}'.format(filepath))
|
||||
PathLog.debug("filepath: {}".format(filepath))
|
||||
return filepath + os.sep
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': 'Path_Sanity',
|
||||
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Sanity",
|
||||
"Check the path job for common errors"),
|
||||
'Accel': "P, S",
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Sanity",
|
||||
"Check the path job for common errors")}
|
||||
return {
|
||||
"Pixmap": "Path_Sanity",
|
||||
"MenuText": QtCore.QT_TRANSLATE_NOOP(
|
||||
"Path_Sanity", "Check the path job for common errors"
|
||||
),
|
||||
"Accel": "P, S",
|
||||
"ToolTip": QtCore.QT_TRANSLATE_NOOP(
|
||||
"Path_Sanity", "Check the path job for common errors"
|
||||
),
|
||||
}
|
||||
|
||||
def IsActive(self):
|
||||
obj = FreeCADGui.Selection.getSelectionEx()[0].Object
|
||||
@@ -141,7 +147,7 @@ class CommandPathSanity:
|
||||
view.showNormal()
|
||||
view.resize(320, 320)
|
||||
|
||||
imagepath = self.outputpath + '{}'.format(imageName)
|
||||
imagepath = self.outputpath + "{}".format(imageName)
|
||||
|
||||
aview.viewIsometric()
|
||||
FreeCADGui.Selection.clearSelection()
|
||||
@@ -149,8 +155,8 @@ class CommandPathSanity:
|
||||
FreeCADGui.Selection.addSelection(obj)
|
||||
FreeCADGui.SendMsgToActiveView("ViewSelection")
|
||||
FreeCADGui.Selection.clearSelection()
|
||||
aview.saveImage(imagepath + '.png', 320, 320, 'Current')
|
||||
aview.saveImage(imagepath + '_t.png', 320, 320, 'Transparent')
|
||||
aview.saveImage(imagepath + ".png", 320, 320, "Current")
|
||||
aview.saveImage(imagepath + "_t.png", 320, 320, "Transparent")
|
||||
|
||||
view.showMaximized()
|
||||
|
||||
@@ -230,26 +236,36 @@ class CommandPathSanity:
|
||||
CustomerLabel = translate("Path_Sanity", "Customer")
|
||||
DesignerLabel = translate("Path_Sanity", "Designer")
|
||||
|
||||
d = data['designData']
|
||||
b = data['baseData']
|
||||
d = data["designData"]
|
||||
b = data["baseData"]
|
||||
|
||||
jobname = d['JobLabel']
|
||||
jobname = d["JobLabel"]
|
||||
|
||||
basestable = "!===\n"
|
||||
for key, val in b['bases'].items():
|
||||
for key, val in b["bases"].items():
|
||||
basestable += "! " + key + " ! " + val + "\n"
|
||||
|
||||
basestable += "!==="
|
||||
|
||||
infoTable += "|*" + PartLabel + "* a| " + basestable + " .7+a|" + \
|
||||
"image::" + b['baseimage'] + "[" + PartLabel + "]\n"
|
||||
infoTable += "|*" + SequenceLabel + "*|" + d['Sequence']
|
||||
infoTable += "|*" + JobTypeLabel + "*|" + d['JobType']
|
||||
infoTable += "|*" + DescriptionLabel + "*|" + d['JobDescription']
|
||||
infoTable += "|*" + CADLabel + "*|" + d['FileName']
|
||||
infoTable += "|*" + LastSaveLabel + "*|" + d['LastModifiedDate']
|
||||
infoTable += "|*" + CustomerLabel + "*|" + d['Customer']
|
||||
infoTable += "|*" + DesignerLabel + "*|" + d['Designer']
|
||||
infoTable += (
|
||||
"|*"
|
||||
+ PartLabel
|
||||
+ "* a| "
|
||||
+ basestable
|
||||
+ " .7+a|"
|
||||
+ "image::"
|
||||
+ b["baseimage"]
|
||||
+ "["
|
||||
+ PartLabel
|
||||
+ "]\n"
|
||||
)
|
||||
infoTable += "|*" + SequenceLabel + "*|" + d["Sequence"]
|
||||
infoTable += "|*" + JobTypeLabel + "*|" + d["JobType"]
|
||||
infoTable += "|*" + DescriptionLabel + "*|" + d["JobDescription"]
|
||||
infoTable += "|*" + CADLabel + "*|" + d["FileName"]
|
||||
infoTable += "|*" + LastSaveLabel + "*|" + d["LastModifiedDate"]
|
||||
infoTable += "|*" + CustomerLabel + "*|" + d["Customer"]
|
||||
infoTable += "|*" + DesignerLabel + "*|" + d["Designer"]
|
||||
|
||||
# Generate the markup for the Run Summary Section
|
||||
|
||||
@@ -261,22 +277,34 @@ class CommandPathSanity:
|
||||
coolantLabel = translate("Path_Sanity", "Coolant")
|
||||
jobTotalLabel = translate("Path_Sanity", "TOTAL JOB")
|
||||
|
||||
d = data['runData']
|
||||
d = data["runData"]
|
||||
|
||||
runTable += "|*" + opLabel + "*|*" + zMinLabel + "*|*" + zMaxLabel + \
|
||||
"*|*" + coolantLabel + "*|*" + cycleTimeLabel + "*\n"
|
||||
runTable += (
|
||||
"|*"
|
||||
+ opLabel
|
||||
+ "*|*"
|
||||
+ zMinLabel
|
||||
+ "*|*"
|
||||
+ zMaxLabel
|
||||
+ "*|*"
|
||||
+ coolantLabel
|
||||
+ "*|*"
|
||||
+ cycleTimeLabel
|
||||
+ "*\n"
|
||||
)
|
||||
|
||||
for i in d['items']:
|
||||
runTable += "|{}".format(i['opName'])
|
||||
runTable += "|{}".format(i['minZ'])
|
||||
runTable += "|{}".format(i['maxZ'])
|
||||
runTable += "|{}".format(i['coolantMode'])
|
||||
runTable += "|{}".format(i['cycleTime'])
|
||||
for i in d["items"]:
|
||||
runTable += "|{}".format(i["opName"])
|
||||
runTable += "|{}".format(i["minZ"])
|
||||
runTable += "|{}".format(i["maxZ"])
|
||||
runTable += "|{}".format(i["coolantMode"])
|
||||
runTable += "|{}".format(i["cycleTime"])
|
||||
|
||||
runTable += "|*" + jobTotalLabel + "* |{} |{} |{}".format(
|
||||
d['jobMinZ'],
|
||||
d['jobMaxZ'],
|
||||
d['cycletotal'])
|
||||
runTable += (
|
||||
"|*"
|
||||
+ jobTotalLabel
|
||||
+ "* |{} |{} |{}".format(d["jobMinZ"], d["jobMaxZ"], d["cycletotal"])
|
||||
)
|
||||
|
||||
# Generate the markup for the Tool Data Section
|
||||
toolTables = ""
|
||||
@@ -294,26 +322,50 @@ class CommandPathSanity:
|
||||
shapeLabel = translate("Path_Sanity", "Tool Shape")
|
||||
diameterLabel = translate("Path_Sanity", "Tool Diameter")
|
||||
|
||||
d = data['toolData']
|
||||
d = data["toolData"]
|
||||
|
||||
for key, value in d.items():
|
||||
toolTables += "=== {}: T{}\n".format(toolLabel, key)
|
||||
|
||||
toolTables += "|===\n"
|
||||
|
||||
toolTables += "|*{}*| {} a| image::{}[{}]\n".format(descriptionLabel, value['description'], value['imagepath'], key)
|
||||
toolTables += "|*{}* 2+| {}\n".format(manufLabel, value['manufacturer'])
|
||||
toolTables += "|*{}* 2+| {}\n".format(partNumberLabel, value['partNumber'])
|
||||
toolTables += "|*{}* 2+| {}\n".format(urlLabel, value['url'])
|
||||
toolTables += "|*{}* 2+| {}\n".format(inspectionNotesLabel, value['inspectionNotes'])
|
||||
toolTables += "|*{}* 2+| {}\n".format(shapeLabel, value['shape'])
|
||||
toolTables += "|*{}* 2+| {}\n".format(diameterLabel, value['diameter'])
|
||||
toolTables += "|*{}*| {} a| image::{}[{}]\n".format(
|
||||
descriptionLabel, value["description"], value["imagepath"], key
|
||||
)
|
||||
toolTables += "|*{}* 2+| {}\n".format(manufLabel, value["manufacturer"])
|
||||
toolTables += "|*{}* 2+| {}\n".format(partNumberLabel, value["partNumber"])
|
||||
toolTables += "|*{}* 2+| {}\n".format(urlLabel, value["url"])
|
||||
toolTables += "|*{}* 2+| {}\n".format(
|
||||
inspectionNotesLabel, value["inspectionNotes"]
|
||||
)
|
||||
toolTables += "|*{}* 2+| {}\n".format(shapeLabel, value["shape"])
|
||||
toolTables += "|*{}* 2+| {}\n".format(diameterLabel, value["diameter"])
|
||||
toolTables += "|===\n"
|
||||
|
||||
toolTables += "|===\n"
|
||||
toolTables += "|*" + opLabel + "*|*" + tcLabel + "*|*" + feedLabel + "*|*" + speedLabel + "*\n"
|
||||
for o in value['ops']:
|
||||
toolTables += "|" + o['Operation'] + "|" + o['ToolController'] + "|" + o['Feed'] + "|" + o['Speed'] + "\n"
|
||||
toolTables += (
|
||||
"|*"
|
||||
+ opLabel
|
||||
+ "*|*"
|
||||
+ tcLabel
|
||||
+ "*|*"
|
||||
+ feedLabel
|
||||
+ "*|*"
|
||||
+ speedLabel
|
||||
+ "*\n"
|
||||
)
|
||||
for o in value["ops"]:
|
||||
toolTables += (
|
||||
"|"
|
||||
+ o["Operation"]
|
||||
+ "|"
|
||||
+ o["ToolController"]
|
||||
+ "|"
|
||||
+ o["Feed"]
|
||||
+ "|"
|
||||
+ o["Speed"]
|
||||
+ "\n"
|
||||
)
|
||||
toolTables += "|===\n"
|
||||
|
||||
toolTables += "\n"
|
||||
@@ -325,15 +377,14 @@ class CommandPathSanity:
|
||||
zDimLabel = translate("Path_Sanity", "Z Size")
|
||||
materialLabel = translate("Path_Sanity", "Material")
|
||||
|
||||
d = data['stockData']
|
||||
d = data["stockData"]
|
||||
|
||||
stockTable += "|*{}*|{} .4+a|image::{}[stock]\n".format(
|
||||
materialLabel,
|
||||
d['material'],
|
||||
d['stockImage'])
|
||||
stockTable += "|*{}*|{}".format(xDimLabel, d['xLen'])
|
||||
stockTable += "|*{}*|{}".format(yDimLabel, d['yLen'])
|
||||
stockTable += "|*{}*|{}".format(zDimLabel, d['zLen'])
|
||||
materialLabel, d["material"], d["stockImage"]
|
||||
)
|
||||
stockTable += "|*{}*|{}".format(xDimLabel, d["xLen"])
|
||||
stockTable += "|*{}*|{}".format(yDimLabel, d["yLen"])
|
||||
stockTable += "|*{}*|{}".format(zDimLabel, d["zLen"])
|
||||
|
||||
# Generate the markup for the Fixture Section
|
||||
|
||||
@@ -342,16 +393,16 @@ class CommandPathSanity:
|
||||
orderByLabel = translate("Path_Sanity", "Order By")
|
||||
datumLabel = translate("Path_Sanity", "Part Datum")
|
||||
|
||||
d = data['fixtureData']
|
||||
d = data["fixtureData"]
|
||||
|
||||
fixtureTable += "|*{}*|{}\n".format(offsetsLabel, d['fixtures'])
|
||||
fixtureTable += "|*{}*|{}\n".format(orderByLabel, d['orderBy'])
|
||||
fixtureTable += "|*{}* a| image::{}[]".format(datumLabel, d['datumImage'])
|
||||
fixtureTable += "|*{}*|{}\n".format(offsetsLabel, d["fixtures"])
|
||||
fixtureTable += "|*{}*|{}\n".format(orderByLabel, d["orderBy"])
|
||||
fixtureTable += "|*{}* a| image::{}[]".format(datumLabel, d["datumImage"])
|
||||
|
||||
# Generate the markup for the Output Section
|
||||
|
||||
outTable = ""
|
||||
d = data['outputData']
|
||||
d = data["outputData"]
|
||||
|
||||
gcodeFileLabel = translate("Path_Sanity", "Gcode File")
|
||||
lastpostLabel = translate("Path_Sanity", "Last Post Process Date")
|
||||
@@ -363,15 +414,15 @@ class CommandPathSanity:
|
||||
fileSizeLabel = translate("Path_Sanity", "File Size (kbs)")
|
||||
lineCountLabel = translate("Path_Sanity", "Line Count")
|
||||
|
||||
outTable += "|*{}*|{}\n".format(gcodeFileLabel, d['lastgcodefile'])
|
||||
outTable += "|*{}*|{}\n".format(lastpostLabel, d['lastpostprocess'])
|
||||
outTable += "|*{}*|{}\n".format(stopsLabel, d['optionalstops'])
|
||||
outTable += "|*{}*|{}\n".format(programmerLabel, d['programmer'])
|
||||
outTable += "|*{}*|{}\n".format(machineLabel, d['machine'])
|
||||
outTable += "|*{}*|{}\n".format(postLabel, d['postprocessor'])
|
||||
outTable += "|*{}*|{}\n".format(flagsLabel, d['postprocessorFlags'])
|
||||
outTable += "|*{}*|{}\n".format(fileSizeLabel, d['filesize'])
|
||||
outTable += "|*{}*|{}\n".format(lineCountLabel, d['linecount'])
|
||||
outTable += "|*{}*|{}\n".format(gcodeFileLabel, d["lastgcodefile"])
|
||||
outTable += "|*{}*|{}\n".format(lastpostLabel, d["lastpostprocess"])
|
||||
outTable += "|*{}*|{}\n".format(stopsLabel, d["optionalstops"])
|
||||
outTable += "|*{}*|{}\n".format(programmerLabel, d["programmer"])
|
||||
outTable += "|*{}*|{}\n".format(machineLabel, d["machine"])
|
||||
outTable += "|*{}*|{}\n".format(postLabel, d["postprocessor"])
|
||||
outTable += "|*{}*|{}\n".format(flagsLabel, d["postprocessorFlags"])
|
||||
outTable += "|*{}*|{}\n".format(fileSizeLabel, d["filesize"])
|
||||
outTable += "|*{}*|{}\n".format(lineCountLabel, d["linecount"])
|
||||
|
||||
# Generate the markup for the Squawk Section
|
||||
|
||||
@@ -379,15 +430,13 @@ class CommandPathSanity:
|
||||
operatorLabel = translate("Path_Sanity", "Operator")
|
||||
dateLabel = translate("Path_Sanity", "Date")
|
||||
|
||||
squawkTable = "|*{}*|*{}*|*{}*\n".format(noteLabel,
|
||||
operatorLabel,
|
||||
dateLabel)
|
||||
squawkTable = "|*{}*|*{}*|*{}*\n".format(noteLabel, operatorLabel, dateLabel)
|
||||
|
||||
d = data['squawkData']
|
||||
for i in d['items']:
|
||||
squawkTable += "a|{}: {}".format(i['squawkType'], i['Note'])
|
||||
squawkTable += "|{}".format(i['Operator'])
|
||||
squawkTable += "|{}".format(i['Date'])
|
||||
d = data["squawkData"]
|
||||
for i in d["items"]:
|
||||
squawkTable += "a|{}: {}".format(i["squawkType"], i["Note"])
|
||||
squawkTable += "|{}".format(i["Operator"])
|
||||
squawkTable += "|{}".format(i["Date"])
|
||||
squawkTable += "\n"
|
||||
|
||||
# merge template and custom markup
|
||||
@@ -400,20 +449,22 @@ class CommandPathSanity:
|
||||
stockTable=stockTable,
|
||||
fixtureTable=fixtureTable,
|
||||
outTable=outTable,
|
||||
squawkTable=squawkTable)
|
||||
squawkTable=squawkTable,
|
||||
)
|
||||
|
||||
# Save the report
|
||||
|
||||
reportraw = self.outputpath + 'setupreport.asciidoc'
|
||||
reporthtml = self.outputpath + 'setupreport.html'
|
||||
with open(reportraw, 'w') as fd:
|
||||
reportraw = self.outputpath + data["outputData"]["outputfilename"] + ".asciidoc"
|
||||
reporthtml = self.outputpath + data["outputData"]["outputfilename"] + ".html"
|
||||
with open(reportraw, "w") as fd:
|
||||
fd.write(report)
|
||||
fd.close()
|
||||
FreeCAD.Console.PrintMessage('asciidoc file written to {}\n'.format(reportraw))
|
||||
FreeCAD.Console.PrintMessage(
|
||||
"asciidoc file written to {}\n".format(reportraw)
|
||||
)
|
||||
|
||||
try:
|
||||
result = os.system('asciidoctor {} -o {}'.format(reportraw,
|
||||
reporthtml))
|
||||
result = os.system("asciidoctor {} -o {}".format(reportraw, reporthtml))
|
||||
if str(result) == "32512":
|
||||
msg = "asciidoctor not found. html cannot be generated."
|
||||
QtGui.QMessageBox.information(None, "Path Sanity", msg)
|
||||
@@ -431,40 +482,46 @@ class CommandPathSanity:
|
||||
Returns a dictionary of sections
|
||||
"""
|
||||
data = {}
|
||||
data['baseData'] = self.__baseObjectData(obj)
|
||||
data['designData'] = self.__designData(obj)
|
||||
data['toolData'] = self.__toolData(obj)
|
||||
data['runData'] = self.__runData(obj)
|
||||
data['outputData'] = self.__outputData(obj)
|
||||
data['fixtureData'] = self.__fixtureData(obj)
|
||||
data['stockData'] = self.__stockData(obj)
|
||||
data['squawkData'] = self.squawkData
|
||||
data["baseData"] = self.__baseObjectData(obj)
|
||||
data["designData"] = self.__designData(obj)
|
||||
data["toolData"] = self.__toolData(obj)
|
||||
data["runData"] = self.__runData(obj)
|
||||
data["outputData"] = self.__outputData(obj)
|
||||
data["fixtureData"] = self.__fixtureData(obj)
|
||||
data["stockData"] = self.__stockData(obj)
|
||||
data["squawkData"] = self.squawkData
|
||||
return data
|
||||
|
||||
def squawk(self, operator, note, date=datetime.now(), squawkType="NOTE"):
|
||||
squawkType = squawkType if squawkType in \
|
||||
["NOTE", "WARNING", "CAUTION", "TIP"] else "NOTE"
|
||||
squawkType = (
|
||||
squawkType
|
||||
if squawkType in ["NOTE", "WARNING", "CAUTION", "TIP"]
|
||||
else "NOTE"
|
||||
)
|
||||
|
||||
self.squawkData['items'].append({"Date": str(date),
|
||||
"Operator": operator,
|
||||
"Note": note,
|
||||
"squawkType": squawkType})
|
||||
self.squawkData["items"].append(
|
||||
{
|
||||
"Date": str(date),
|
||||
"Operator": operator,
|
||||
"Note": note,
|
||||
"squawkType": squawkType,
|
||||
}
|
||||
)
|
||||
|
||||
def __baseObjectData(self, obj):
|
||||
data = {'baseimage': '',
|
||||
'bases': ''}
|
||||
data = {"baseimage": "", "bases": ""}
|
||||
try:
|
||||
bases = {}
|
||||
for name, count in \
|
||||
PathUtil.keyValueIter(Counter([obj.Proxy.baseObject(obj,
|
||||
o).Label for o in obj.Model.Group])):
|
||||
for name, count in PathUtil.keyValueIter(
|
||||
Counter([obj.Proxy.baseObject(obj, o).Label for o in obj.Model.Group])
|
||||
):
|
||||
bases[name] = str(count)
|
||||
|
||||
data['baseimage'] = self.__makePicture(obj.Model, "baseimage")
|
||||
data['bases'] = bases
|
||||
data["baseimage"] = self.__makePicture(obj.Model, "baseimage")
|
||||
data["bases"] = bases
|
||||
|
||||
except Exception as e:
|
||||
data['errors'] = e
|
||||
data["errors"] = e
|
||||
self.squawk("PathSanity(__baseObjectData)", e, squawkType="CAUTION")
|
||||
|
||||
return data
|
||||
@@ -475,21 +532,23 @@ class CommandPathSanity:
|
||||
Returns information about issues and concerns (squawks)
|
||||
"""
|
||||
|
||||
data = {'FileName': '',
|
||||
'LastModifiedDate': '',
|
||||
'Customer': '',
|
||||
'Designer': '',
|
||||
'JobDescription': '',
|
||||
'JobLabel': '',
|
||||
'Sequence': '',
|
||||
'JobType': ''}
|
||||
data = {
|
||||
"FileName": "",
|
||||
"LastModifiedDate": "",
|
||||
"Customer": "",
|
||||
"Designer": "",
|
||||
"JobDescription": "",
|
||||
"JobLabel": "",
|
||||
"Sequence": "",
|
||||
"JobType": "",
|
||||
}
|
||||
try:
|
||||
data['FileName'] = obj.Document.FileName
|
||||
data['LastModifiedDate'] = str(obj.Document.LastModifiedDate)
|
||||
data['Customer'] = obj.Document.Company
|
||||
data['Designer'] = obj.Document.LastModifiedBy
|
||||
data['JobDescription'] = obj.Description
|
||||
data['JobLabel'] = obj.Label
|
||||
data["FileName"] = obj.Document.FileName
|
||||
data["LastModifiedDate"] = str(obj.Document.LastModifiedDate)
|
||||
data["Customer"] = obj.Document.Company
|
||||
data["Designer"] = obj.Document.LastModifiedBy
|
||||
data["JobDescription"] = obj.Description
|
||||
data["JobLabel"] = obj.Label
|
||||
|
||||
n = 0
|
||||
m = 0
|
||||
@@ -499,11 +558,11 @@ class CommandPathSanity:
|
||||
m += 1
|
||||
if i is obj:
|
||||
n = m
|
||||
data['Sequence'] = "{} of {}".format(n, m)
|
||||
data['JobType'] = "2.5D Milling" # improve after job types added
|
||||
data["Sequence"] = "{} of {}".format(n, m)
|
||||
data["JobType"] = "2.5D Milling" # improve after job types added
|
||||
|
||||
except Exception as e:
|
||||
data['errors'] = e
|
||||
data["errors"] = e
|
||||
self.squawk("PathSanity(__designData)", e, squawkType="CAUTION")
|
||||
|
||||
return data
|
||||
@@ -518,83 +577,102 @@ class CommandPathSanity:
|
||||
|
||||
try:
|
||||
for TC in obj.Tools.Group:
|
||||
if not hasattr(TC.Tool, 'BitBody'):
|
||||
self.squawk("PathSanity",
|
||||
"Tool number {} is a legacy tool. Legacy tools not \
|
||||
supported by Path-Sanity".format(TC.ToolNumber),
|
||||
squawkType="WARNING")
|
||||
if not hasattr(TC.Tool, "BitBody"):
|
||||
self.squawk(
|
||||
"PathSanity",
|
||||
"Tool number {} is a legacy tool. Legacy tools not \
|
||||
supported by Path-Sanity".format(
|
||||
TC.ToolNumber
|
||||
),
|
||||
squawkType="WARNING",
|
||||
)
|
||||
continue # skip old-style tools
|
||||
tooldata = data.setdefault(str(TC.ToolNumber), {})
|
||||
bitshape = tooldata.setdefault('BitShape', "")
|
||||
bitshape = tooldata.setdefault("BitShape", "")
|
||||
if bitshape not in ["", TC.Tool.BitShape]:
|
||||
self.squawk("PathSanity",
|
||||
"Tool number {} used by multiple tools".format(TC.ToolNumber),
|
||||
squawkType="CAUTION")
|
||||
tooldata['bitShape'] = TC.Tool.BitShape
|
||||
tooldata['description'] = TC.Tool.Label
|
||||
tooldata['manufacturer'] = ""
|
||||
tooldata['url'] = ""
|
||||
tooldata['inspectionNotes'] = ""
|
||||
tooldata['diameter'] = str(TC.Tool.Diameter)
|
||||
tooldata['shape'] = TC.Tool.ShapeName
|
||||
self.squawk(
|
||||
"PathSanity",
|
||||
"Tool number {} used by multiple tools".format(TC.ToolNumber),
|
||||
squawkType="CAUTION",
|
||||
)
|
||||
tooldata["bitShape"] = TC.Tool.BitShape
|
||||
tooldata["description"] = TC.Tool.Label
|
||||
tooldata["manufacturer"] = ""
|
||||
tooldata["url"] = ""
|
||||
tooldata["inspectionNotes"] = ""
|
||||
tooldata["diameter"] = str(TC.Tool.Diameter)
|
||||
tooldata["shape"] = TC.Tool.ShapeName
|
||||
|
||||
tooldata['partNumber'] = ""
|
||||
tooldata["partNumber"] = ""
|
||||
imagedata = TC.Tool.Proxy.getBitThumbnail(TC.Tool)
|
||||
imagepath = '{}T{}.png'.format(self.outputpath, TC.ToolNumber)
|
||||
tooldata['feedrate'] = str(TC.HorizFeed)
|
||||
imagepath = "{}T{}.png".format(self.outputpath, TC.ToolNumber)
|
||||
tooldata["feedrate"] = str(TC.HorizFeed)
|
||||
if TC.HorizFeed.Value == 0.0:
|
||||
self.squawk("PathSanity",
|
||||
self.squawk(
|
||||
"PathSanity",
|
||||
"Tool Controller '{}' has no feedrate".format(TC.Label),
|
||||
squawkType="WARNING")
|
||||
squawkType="WARNING",
|
||||
)
|
||||
|
||||
tooldata['spindlespeed'] = str(TC.SpindleSpeed)
|
||||
tooldata["spindlespeed"] = str(TC.SpindleSpeed)
|
||||
if TC.SpindleSpeed == 0.0:
|
||||
self.squawk("PathSanity",
|
||||
self.squawk(
|
||||
"PathSanity",
|
||||
"Tool Controller '{}' has no spindlespeed".format(TC.Label),
|
||||
squawkType="WARNING")
|
||||
squawkType="WARNING",
|
||||
)
|
||||
|
||||
with open(imagepath, 'wb') as fd:
|
||||
with open(imagepath, "wb") as fd:
|
||||
fd.write(imagedata)
|
||||
fd.close()
|
||||
tooldata['imagepath'] = imagepath
|
||||
tooldata["imagepath"] = imagepath
|
||||
|
||||
used = False
|
||||
for op in obj.Operations.Group:
|
||||
if hasattr(op, "ToolController") and op.ToolController is TC:
|
||||
used = True
|
||||
tooldata.setdefault('ops', []).append(
|
||||
{"Operation": op.Label,
|
||||
"ToolController": TC.Label,
|
||||
"Feed": str(TC.HorizFeed),
|
||||
"Speed": str(TC.SpindleSpeed)})
|
||||
tooldata.setdefault("ops", []).append(
|
||||
{
|
||||
"Operation": op.Label,
|
||||
"ToolController": TC.Label,
|
||||
"Feed": str(TC.HorizFeed),
|
||||
"Speed": str(TC.SpindleSpeed),
|
||||
}
|
||||
)
|
||||
|
||||
if used is False:
|
||||
tooldata.setdefault('ops', [])
|
||||
self.squawk("PathSanity",
|
||||
tooldata.setdefault("ops", [])
|
||||
self.squawk(
|
||||
"PathSanity",
|
||||
"Tool Controller '{}' is not used".format(TC.Label),
|
||||
squawkType="WARNING")
|
||||
squawkType="WARNING",
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
data['errors'] = e
|
||||
data["errors"] = e
|
||||
self.squawk("PathSanity(__toolData)", e, squawkType="CAUTION")
|
||||
|
||||
return data
|
||||
|
||||
def __runData(self, obj):
|
||||
data = {'cycletotal': '',
|
||||
'jobMinZ': '',
|
||||
'jobMaxZ': '',
|
||||
'jobDescription': '',
|
||||
'items': []}
|
||||
data = {
|
||||
"cycletotal": "",
|
||||
"jobMinZ": "",
|
||||
"jobMaxZ": "",
|
||||
"jobDescription": "",
|
||||
"items": [],
|
||||
}
|
||||
try:
|
||||
data['cycletotal'] = str(obj.CycleTime)
|
||||
data['jobMinZ'] = FreeCAD.Units.Quantity(obj.Path.BoundBox.ZMin,
|
||||
FreeCAD.Units.Length).UserString
|
||||
data['jobMaxZ'] = FreeCAD.Units.Quantity(obj.Path.BoundBox.ZMax,
|
||||
FreeCAD.Units.Length).UserString
|
||||
data['jobDescription'] = obj.Description
|
||||
data["cycletotal"] = str(obj.CycleTime)
|
||||
data["jobMinZ"] = FreeCAD.Units.Quantity(
|
||||
obj.Path.BoundBox.ZMin, FreeCAD.Units.Length
|
||||
).UserString
|
||||
data["jobMaxZ"] = FreeCAD.Units.Quantity(
|
||||
obj.Path.BoundBox.ZMax, FreeCAD.Units.Length
|
||||
).UserString
|
||||
data["jobDescription"] = obj.Description
|
||||
|
||||
data['items'] = []
|
||||
data["items"] = []
|
||||
for op in obj.Operations.Group:
|
||||
|
||||
oplabel = op.Label
|
||||
@@ -605,69 +683,79 @@ class CommandPathSanity:
|
||||
while len(o.ViewObject.claimChildren()) != 0: # dressup
|
||||
oplabel = "{}:{}".format(oplabel, o.Base.Label)
|
||||
o = o.Base
|
||||
if hasattr(o, 'CycleTime'):
|
||||
if hasattr(o, "CycleTime"):
|
||||
ctime = o.CycleTime
|
||||
cool = o.CoolantMode if hasattr(o, "CoolantMode") else cool
|
||||
|
||||
if hasattr(op, 'Active') and not op.Active:
|
||||
if hasattr(op, "Active") and not op.Active:
|
||||
oplabel = "{} (INACTIVE)".format(oplabel)
|
||||
ctime = 0.0
|
||||
|
||||
if op.Path.BoundBox.isValid():
|
||||
zmin = FreeCAD.Units.Quantity(op.Path.BoundBox.ZMin,
|
||||
FreeCAD.Units.Length).UserString
|
||||
zmax = FreeCAD.Units.Quantity(op.Path.BoundBox.ZMax,
|
||||
FreeCAD.Units.Length).UserString
|
||||
zmin = FreeCAD.Units.Quantity(
|
||||
op.Path.BoundBox.ZMin, FreeCAD.Units.Length
|
||||
).UserString
|
||||
zmax = FreeCAD.Units.Quantity(
|
||||
op.Path.BoundBox.ZMax, FreeCAD.Units.Length
|
||||
).UserString
|
||||
else:
|
||||
zmin = ''
|
||||
zmax = ''
|
||||
zmin = ""
|
||||
zmax = ""
|
||||
|
||||
opdata = {"opName": oplabel,
|
||||
"minZ": zmin,
|
||||
"maxZ": zmax,
|
||||
"cycleTime": ctime,
|
||||
"coolantMode": cool}
|
||||
data['items'].append(opdata)
|
||||
opdata = {
|
||||
"opName": oplabel,
|
||||
"minZ": zmin,
|
||||
"maxZ": zmax,
|
||||
"cycleTime": ctime,
|
||||
"coolantMode": cool,
|
||||
}
|
||||
data["items"].append(opdata)
|
||||
|
||||
except Exception as e:
|
||||
data['errors'] = e
|
||||
data["errors"] = e
|
||||
self.squawk("PathSanity(__runData)", e, squawkType="CAUTION")
|
||||
|
||||
return data
|
||||
|
||||
def __stockData(self, obj):
|
||||
data = {'xLen': '',
|
||||
'yLen': '',
|
||||
'zLen': '',
|
||||
'material': '',
|
||||
'stockImage': ''}
|
||||
data = {"xLen": "", "yLen": "", "zLen": "", "material": "", "stockImage": ""}
|
||||
|
||||
try:
|
||||
bb = obj.Stock.Shape.BoundBox
|
||||
data['xLen'] = FreeCAD.Units.Quantity(bb.XLength, FreeCAD.Units.Length).UserString
|
||||
data['yLen'] = FreeCAD.Units.Quantity(bb.YLength, FreeCAD.Units.Length).UserString
|
||||
data['zLen'] = FreeCAD.Units.Quantity(bb.ZLength, FreeCAD.Units.Length).UserString
|
||||
data["xLen"] = FreeCAD.Units.Quantity(
|
||||
bb.XLength, FreeCAD.Units.Length
|
||||
).UserString
|
||||
data["yLen"] = FreeCAD.Units.Quantity(
|
||||
bb.YLength, FreeCAD.Units.Length
|
||||
).UserString
|
||||
data["zLen"] = FreeCAD.Units.Quantity(
|
||||
bb.ZLength, FreeCAD.Units.Length
|
||||
).UserString
|
||||
|
||||
data['material'] = "Not Specified"
|
||||
if hasattr(obj.Stock, 'Material'):
|
||||
data["material"] = "Not Specified"
|
||||
if hasattr(obj.Stock, "Material"):
|
||||
if obj.Stock.Material is not None:
|
||||
data['material'] = obj.Stock.Material.Material['Name']
|
||||
data["material"] = obj.Stock.Material.Material["Name"]
|
||||
|
||||
if data['material'] == "Not Specified":
|
||||
self.squawk("PathSanity", "Consider Specifying the Stock Material", squawkType="TIP")
|
||||
if data["material"] == "Not Specified":
|
||||
self.squawk(
|
||||
"PathSanity",
|
||||
"Consider Specifying the Stock Material",
|
||||
squawkType="TIP",
|
||||
)
|
||||
|
||||
data['stockImage'] = self.__makePicture(obj.Stock, "stockImage")
|
||||
data["stockImage"] = self.__makePicture(obj.Stock, "stockImage")
|
||||
except Exception as e:
|
||||
data['errors'] = e
|
||||
data["errors"] = e
|
||||
self.squawk("PathSanity(__stockData)", e, squawkType="CAUTION")
|
||||
|
||||
return data
|
||||
|
||||
def __fixtureData(self, obj):
|
||||
data = {'fixtures': '', 'orderBy': '', 'datumImage': ''}
|
||||
data = {"fixtures": "", "orderBy": "", "datumImage": ""}
|
||||
try:
|
||||
data['fixtures'] = str(obj.Fixtures)
|
||||
data['orderBy'] = str(obj.OrderOutputBy)
|
||||
data["fixtures"] = str(obj.Fixtures)
|
||||
data["orderBy"] = str(obj.OrderOutputBy)
|
||||
|
||||
aview = FreeCADGui.activeDocument().activeView()
|
||||
aview.setAnimationEnabled(False)
|
||||
@@ -681,7 +769,7 @@ class CommandPathSanity:
|
||||
view.showNormal()
|
||||
view.resize(320, 320)
|
||||
|
||||
imagepath = '{}origin'.format(self.outputpath)
|
||||
imagepath = "{}origin".format(self.outputpath)
|
||||
|
||||
FreeCADGui.Selection.clearSelection()
|
||||
FreeCADGui.SendMsgToActiveView("PerspectiveCamera")
|
||||
@@ -691,8 +779,8 @@ class CommandPathSanity:
|
||||
FreeCADGui.SendMsgToActiveView("ViewSelection")
|
||||
FreeCADGui.Selection.clearSelection()
|
||||
obj.ViewObject.Proxy.editObject(obj)
|
||||
aview.saveImage('{}.png'.format(imagepath), 320, 320, 'Current')
|
||||
aview.saveImage('{}_t.png'.format(imagepath), 320, 320, 'Transparent')
|
||||
aview.saveImage("{}.png".format(imagepath), 320, 320, "Current")
|
||||
aview.saveImage("{}_t.png".format(imagepath), 320, 320, "Transparent")
|
||||
obj.ViewObject.Proxy.uneditObject(obj)
|
||||
obj.Visibility = True
|
||||
obj.Operations.Visibility = True
|
||||
@@ -700,47 +788,55 @@ class CommandPathSanity:
|
||||
view.showMaximized()
|
||||
|
||||
aview.setAnimationEnabled(True)
|
||||
data['datumImage'] = '{}_t.png'.format(imagepath)
|
||||
data["datumImage"] = "{}_t.png".format(imagepath)
|
||||
|
||||
except Exception as e:
|
||||
data['errors'] = e
|
||||
data["errors"] = e
|
||||
self.squawk("PathSanity(__fixtureData)", e, squawkType="CAUTION")
|
||||
|
||||
return data
|
||||
|
||||
def __outputData(self, obj):
|
||||
data = {'lastpostprocess': '',
|
||||
'lastgcodefile': '',
|
||||
'optionalstops': '',
|
||||
'programmer': '',
|
||||
'machine': '',
|
||||
'postprocessor': '',
|
||||
'postprocessorFlags': '',
|
||||
'filesize': '',
|
||||
'linecount': ''}
|
||||
data = {
|
||||
"lastpostprocess": "",
|
||||
"lastgcodefile": "",
|
||||
"optionalstops": "",
|
||||
"programmer": "",
|
||||
"machine": "",
|
||||
"postprocessor": "",
|
||||
"postprocessorFlags": "",
|
||||
"filesize": "",
|
||||
"linecount": "",
|
||||
"outputfilename": "setupreport",
|
||||
}
|
||||
try:
|
||||
data['lastpostprocess'] = str(obj.LastPostProcessDate)
|
||||
data['lastgcodefile'] = str(obj.LastPostProcessOutput)
|
||||
data['optionalstops'] = "False"
|
||||
data['programmer'] = ""
|
||||
data['machine'] = ""
|
||||
data['postprocessor'] = str(obj.PostProcessor)
|
||||
data['postprocessorFlags'] = str(obj.PostProcessorArgs)
|
||||
data["lastpostprocess"] = str(obj.LastPostProcessDate)
|
||||
data["lastgcodefile"] = str(obj.LastPostProcessOutput)
|
||||
data["optionalstops"] = "False"
|
||||
data["programmer"] = ""
|
||||
data["machine"] = ""
|
||||
data["postprocessor"] = str(obj.PostProcessor)
|
||||
data["postprocessorFlags"] = str(obj.PostProcessorArgs)
|
||||
|
||||
if obj.PostProcessorOutputFile != "":
|
||||
fname = obj.PostProcessorOutputFile
|
||||
data["outputfilename"] = os.path.splitext(os.path.basename(fname))[0]
|
||||
for op in obj.Operations.Group:
|
||||
if isinstance(op.Proxy, PathScripts.PathStop.Stop) and op.Stop is True:
|
||||
data['optionalstops'] = "True"
|
||||
data["optionalstops"] = "True"
|
||||
|
||||
if obj.LastPostProcessOutput == "":
|
||||
data['filesize'] = str(0.0)
|
||||
data['linecount'] = str(0)
|
||||
data["filesize"] = str(0.0)
|
||||
data["linecount"] = str(0)
|
||||
self.squawk("PathSanity", "The Job has not been post-processed")
|
||||
else:
|
||||
data['filesize'] = str(os.path.getsize(obj.LastPostProcessOutput))
|
||||
data['linecount'] = str(sum(1 for line in open(obj.LastPostProcessOutput)))
|
||||
data["filesize"] = str(os.path.getsize(obj.LastPostProcessOutput))
|
||||
data["linecount"] = str(
|
||||
sum(1 for line in open(obj.LastPostProcessOutput))
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
data['errors'] = e
|
||||
data["errors"] = e
|
||||
self.squawk("PathSanity(__outputData)", e, squawkType="CAUTION")
|
||||
|
||||
return data
|
||||
@@ -748,4 +844,4 @@ class CommandPathSanity:
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
# register the FreeCAD command
|
||||
FreeCADGui.addCommand('Path_Sanity', CommandPathSanity())
|
||||
FreeCADGui.addCommand("Path_Sanity", CommandPathSanity())
|
||||
|
||||
@@ -34,7 +34,7 @@ __doc__ = "A container for all default values and job specific configuration val
|
||||
|
||||
_RegisteredOps = {}
|
||||
|
||||
PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
|
||||
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
|
||||
# PathLog.trackModule(PathLog.thisModule())
|
||||
|
||||
|
||||
|
||||
@@ -380,7 +380,10 @@ class ToolBit(object):
|
||||
if PathPreferences.toolsStoreAbsolutePaths():
|
||||
attrs['shape'] = obj.BitShape
|
||||
else:
|
||||
attrs['shape'] = findRelativePathShape(obj.BitShape)
|
||||
# attrs['shape'] = findRelativePathShape(obj.BitShape)
|
||||
# Extract the name of the shape file
|
||||
__, filShp = os.path.split(obj.BitShape) # __ is an ignored placeholder acknowledged by LGTM
|
||||
attrs['shape'] = str(filShp)
|
||||
params = {}
|
||||
for name in obj.BitPropertyNames:
|
||||
params[name] = PathUtil.getPropertyValueString(obj, name)
|
||||
|
||||
@@ -620,9 +620,13 @@ class ToolBitLibrary(object):
|
||||
toolNr = self.toolModel.data(self.toolModel.index(row, 0), PySide.QtCore.Qt.EditRole)
|
||||
toolPath = self.toolModel.data(self.toolModel.index(row, 0), _PathRole)
|
||||
if PathPreferences.toolsStoreAbsolutePaths():
|
||||
tools.append({'nr': toolNr, 'path': toolPath})
|
||||
bitPath = toolPath
|
||||
else:
|
||||
tools.append({'nr': toolNr, 'path': PathToolBit.findRelativePathTool(toolPath)})
|
||||
# bitPath = PathToolBit.findRelativePathTool(toolPath)
|
||||
# Extract the name of the shape file
|
||||
__, filShp = os.path.split(toolPath) # __ is an ignored placeholder acknowledged by LGTM
|
||||
bitPath = str(filShp)
|
||||
tools.append({'nr': toolNr, 'path': bitPath})
|
||||
|
||||
if self.path is not None:
|
||||
with open(self.path, 'w') as fp:
|
||||
|
||||
@@ -186,7 +186,7 @@ class _Geometry(object):
|
||||
def _calculate_depth(MIC, geom):
|
||||
# given a maximum inscribed circle (MIC) and tool angle,
|
||||
# return depth of cut relative to zStart.
|
||||
depth = geom.start - round(MIC / geom.scale, 4)
|
||||
depth = geom.start - round(MIC * geom.scale, 4)
|
||||
PathLog.debug('zStart value: {} depth: {}'.format(geom.start, depth))
|
||||
|
||||
return max(depth, geom.stop)
|
||||
|
||||
@@ -30,7 +30,6 @@ import datetime
|
||||
import shlex
|
||||
import os.path
|
||||
from PathScripts import PostUtils
|
||||
from PathScripts import PathUtils
|
||||
|
||||
TOOLTIP = '''
|
||||
This is a postprocessor file for the Path workbench. It is used to
|
||||
@@ -154,7 +153,7 @@ def processArguments(argstring):
|
||||
if args.no_tlo:
|
||||
USE_TLO = False
|
||||
if args.no_axis_modal:
|
||||
OUTPUT_DOUBLES = true
|
||||
OUTPUT_DOUBLES = True
|
||||
|
||||
except Exception: # pylint: disable=broad-except
|
||||
return False
|
||||
@@ -171,7 +170,7 @@ def export(objectslist, filename, argstring):
|
||||
global UNIT_SPEED_FORMAT
|
||||
global HORIZRAPID
|
||||
global VERTRAPID
|
||||
|
||||
|
||||
for obj in objectslist:
|
||||
if not hasattr(obj, "Path"):
|
||||
print("the object " + obj.Name + " is not a path. Please select only path and Compounds.")
|
||||
@@ -206,34 +205,10 @@ def export(objectslist, filename, argstring):
|
||||
if not obj.Base.Active:
|
||||
continue
|
||||
|
||||
# fetch machine details
|
||||
job = PathUtils.findParentJob(obj)
|
||||
|
||||
myMachine = 'not set'
|
||||
|
||||
if hasattr(job, "MachineName"):
|
||||
myMachine = job.MachineName
|
||||
|
||||
if hasattr(job, "MachineUnits"):
|
||||
if job.MachineUnits == "Metric":
|
||||
UNITS = "G21"
|
||||
UNIT_FORMAT = 'mm'
|
||||
UNIT_SPEED_FORMAT = 'mm/min'
|
||||
else:
|
||||
UNITS = "G20"
|
||||
UNIT_FORMAT = 'in'
|
||||
UNIT_SPEED_FORMAT = 'in/min'
|
||||
|
||||
if hasattr(job, "SetupSheet"):
|
||||
if hasattr(job.SetupSheet, "HorizRapid"):
|
||||
HORIZRAPID = Units.Quantity(job.SetupSheet.HorizRapid, FreeCAD.Units.Velocity)
|
||||
if hasattr(job.SetupSheet, "VertRapid"):
|
||||
VERTRAPID = Units.Quantity(job.SetupSheet.HorizRapid, FreeCAD.Units.Velocity)
|
||||
|
||||
# do the pre_op
|
||||
if OUTPUT_COMMENTS:
|
||||
gcode += linenumber() + "(BEGIN OPERATION: %s)\n" % obj.Label.upper()
|
||||
gcode += linenumber() + "(MACHINE: %s, %s)\n" % (myMachine.upper(), UNIT_SPEED_FORMAT.upper())
|
||||
gcode += linenumber() + "(MACHINE UNITS: %s)\n" % (UNIT_SPEED_FORMAT.upper())
|
||||
for line in PRE_OPERATION.splitlines(True):
|
||||
gcode += linenumber() + line
|
||||
|
||||
@@ -459,7 +434,6 @@ def parse(pathobj):
|
||||
outstring.append(param + str(int(c.Parameters['D'])))
|
||||
elif param == 'S':
|
||||
outstring.append(param + str(int(c.Parameters['S'])))
|
||||
currentSpeed = int(c.Parameters['S'])
|
||||
else:
|
||||
if (not OUTPUT_DOUBLES) and (param in currLocation) and (currLocation[param] == c.Parameters[param]):
|
||||
continue
|
||||
@@ -482,7 +456,6 @@ def parse(pathobj):
|
||||
# Check for Tool Change:
|
||||
if command == 'M6':
|
||||
# stop the spindle
|
||||
currentSpeed = 0
|
||||
out += linenumber() + "M5\n"
|
||||
for line in TOOL_CHANGE.splitlines(True):
|
||||
out += linenumber() + line
|
||||
|
||||
@@ -223,9 +223,9 @@ def export(objectslist, filename, argstring):
|
||||
# Check canned cycles for drilling
|
||||
if TRANSLATE_DRILL_CYCLES:
|
||||
if len(SUPPRESS_COMMANDS) == 0:
|
||||
SUPPRESS_COMMANDS = ['G98', 'G80']
|
||||
SUPPRESS_COMMANDS = ['G99', 'G98', 'G80']
|
||||
else:
|
||||
SUPPRESS_COMMANDS += ['G98', 'G80']
|
||||
SUPPRESS_COMMANDS += ['G99', 'G98', 'G80']
|
||||
|
||||
# Write the preamble
|
||||
if OUTPUT_COMMENTS:
|
||||
@@ -305,6 +305,9 @@ def export(objectslist, filename, argstring):
|
||||
gcode += linenumber() + '(Coolant Off:' + coolantMode + ')\n'
|
||||
gcode += linenumber() +'M9' + '\n'
|
||||
|
||||
if RETURN_TO:
|
||||
gcode += linenumber() + "G0 X%s Y%s\n" % tuple(RETURN_TO)
|
||||
|
||||
# do the post_amble
|
||||
if OUTPUT_BCNC:
|
||||
gcode += linenumber() + "(Block-name: post_amble)\n"
|
||||
@@ -315,9 +318,6 @@ def export(objectslist, filename, argstring):
|
||||
for line in POSTAMBLE.splitlines(True):
|
||||
gcode += linenumber() + line
|
||||
|
||||
if RETURN_TO:
|
||||
gcode += linenumber() + "G0 X%s Y%s" % tuple(RETURN_TO)
|
||||
|
||||
# show the gCode result dialog
|
||||
if FreeCAD.GuiUp and SHOW_EDITOR:
|
||||
dia = PostUtils.GCodeEditorDialog()
|
||||
|
||||
@@ -20,14 +20,10 @@
|
||||
|
||||
# HEDENHAIN Post-Processor for FreeCAD
|
||||
|
||||
import FreeCAD
|
||||
from FreeCAD import Units
|
||||
import argparse
|
||||
import time
|
||||
import shlex
|
||||
import PathScripts
|
||||
from PathScripts import PostUtils
|
||||
from PathScripts import PathUtils
|
||||
import math
|
||||
|
||||
#**************************************************************************#
|
||||
@@ -261,11 +257,8 @@ def export(objectslist, filename, argstring):
|
||||
global LBLIZE_STAUS
|
||||
|
||||
Object_Kind = None
|
||||
Feed_Rapid = False
|
||||
Feed = 0
|
||||
Spindle_RPM = 0
|
||||
Spindle_Active = False
|
||||
ToolId = ""
|
||||
Compensation = "0"
|
||||
params = [
|
||||
'X', 'Y', 'Z',
|
||||
@@ -360,22 +353,14 @@ def export(objectslist, filename, argstring):
|
||||
|
||||
for c in obj.Path.Commands:
|
||||
Cmd_Count += 1
|
||||
outstring = []
|
||||
command = c.Name
|
||||
if command != 'G0':
|
||||
command = command.replace('G0','G') # normalize: G01 -> G1
|
||||
Feed_Rapid = False
|
||||
else:
|
||||
Feed_Rapid = True
|
||||
|
||||
for param in params:
|
||||
if param in c.Parameters:
|
||||
if param == 'F':
|
||||
Feed = c.Parameters['F']
|
||||
elif param == 'S':
|
||||
Spindle_RPM = c.Parameters['S'] # Could be deleted if tool it's OK
|
||||
elif param == 'T':
|
||||
ToolId = c.Parameters['T'] # Could be deleted if tool it's OK
|
||||
|
||||
if command == 'G90':
|
||||
G_FUNCTION_STORE['G90'] = True
|
||||
@@ -474,21 +459,21 @@ def export(objectslist, filename, argstring):
|
||||
|
||||
def HEIDEN_Begin(ActualJob): #use Label for program name
|
||||
global UNITS
|
||||
JobParent = PathUtils.findParentJob(ActualJob[0])
|
||||
if hasattr(JobParent, "Label"):
|
||||
program_id = JobParent.Label
|
||||
else:
|
||||
program_id = "NEW"
|
||||
return "BEGIN PGM " + str(program_id) + " " + UNITS
|
||||
# JobParent = PathUtils.findParentJob(ActualJob[0])
|
||||
# if hasattr(JobParent, "Label"):
|
||||
# program_id = JobParent.Label
|
||||
# else:
|
||||
# program_id = "NEW"
|
||||
return "BEGIN PGM {}".format(UNITS)
|
||||
|
||||
def HEIDEN_End(ActualJob): #use Label for program name
|
||||
global UNITS
|
||||
JobParent = PathUtils.findParentJob(ActualJob[0])
|
||||
if hasattr(JobParent, "Label"):
|
||||
program_id = JobParent.Label
|
||||
else:
|
||||
program_id = "NEW"
|
||||
return "END PGM " + program_id + " " + UNITS
|
||||
# JobParent = PathUtils.findParentJob(ActualJob[0])
|
||||
# if hasattr(JobParent, "Label"):
|
||||
# program_id = JobParent.Label
|
||||
# else:
|
||||
# program_id = "NEW"
|
||||
return "END PGM {}".format(UNITS)
|
||||
|
||||
#def HEIDEN_ToolDef(tool_id, tool_length, tool_radius): # old machines don't have tool table, need tooldef list
|
||||
# return "TOOL DEF " + tool_id + " R" + "{:.3f}".format(tool_length) + " L" + "{:.3f}".format(tool_radius)
|
||||
|
||||
@@ -29,7 +29,6 @@ import argparse
|
||||
import datetime
|
||||
import shlex
|
||||
from PathScripts import PostUtils
|
||||
from PathScripts import PathUtils
|
||||
|
||||
TOOLTIP = '''
|
||||
This is a postprocessor file for the Path workbench. It is used to
|
||||
@@ -193,28 +192,10 @@ def export(objectslist, filename, argstring):
|
||||
if not obj.Base.Active:
|
||||
continue
|
||||
|
||||
# fetch machine details
|
||||
job = PathUtils.findParentJob(obj)
|
||||
|
||||
myMachine = 'not set'
|
||||
|
||||
if hasattr(job, "MachineName"):
|
||||
myMachine = job.MachineName
|
||||
|
||||
if hasattr(job, "MachineUnits"):
|
||||
if job.MachineUnits == "Metric":
|
||||
UNITS = "G21"
|
||||
UNIT_FORMAT = 'mm'
|
||||
UNIT_SPEED_FORMAT = 'mm/min'
|
||||
else:
|
||||
UNITS = "G20"
|
||||
UNIT_FORMAT = 'in'
|
||||
UNIT_SPEED_FORMAT = 'in/min'
|
||||
|
||||
# do the pre_op
|
||||
if OUTPUT_COMMENTS:
|
||||
gcode += linenumber() + "(begin operation: %s)\n" % obj.Label
|
||||
gcode += linenumber() + "(machine: %s, %s)\n" % (myMachine, UNIT_SPEED_FORMAT)
|
||||
gcode += linenumber() + "(machine units: %s)\n" % (UNIT_SPEED_FORMAT)
|
||||
for line in PRE_OPERATION.splitlines(True):
|
||||
gcode += linenumber() + line
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ import argparse
|
||||
import datetime
|
||||
import shlex
|
||||
from PathScripts import PostUtils
|
||||
from PathScripts import PathUtils
|
||||
|
||||
TOOLTIP = '''
|
||||
This is a postprocessor file for the Path workbench. It is used to
|
||||
@@ -161,8 +160,6 @@ def export(objectslist, filename, argstring):
|
||||
global UNITS
|
||||
global UNIT_FORMAT
|
||||
global UNIT_SPEED_FORMAT
|
||||
global HORIZRAPID
|
||||
global VERTRAPID
|
||||
|
||||
for obj in objectslist:
|
||||
if not hasattr(obj, "Path"):
|
||||
@@ -195,34 +192,10 @@ def export(objectslist, filename, argstring):
|
||||
if not obj.Base.Active:
|
||||
continue
|
||||
|
||||
# fetch machine details
|
||||
job = PathUtils.findParentJob(obj)
|
||||
|
||||
myMachine = 'not set'
|
||||
|
||||
if hasattr(job, "MachineName"):
|
||||
myMachine = job.MachineName
|
||||
|
||||
if hasattr(job, "MachineUnits"):
|
||||
if job.MachineUnits == "Metric":
|
||||
UNITS = "G21"
|
||||
UNIT_FORMAT = 'mm'
|
||||
UNIT_SPEED_FORMAT = 'mm/min'
|
||||
else:
|
||||
UNITS = "G20"
|
||||
UNIT_FORMAT = 'in'
|
||||
UNIT_SPEED_FORMAT = 'in/min'
|
||||
|
||||
if hasattr(job, "SetupSheet"):
|
||||
if hasattr(job.SetupSheet, "HorizRapid"):
|
||||
HORIZRAPID = Units.Quantity(job.SetupSheet.HorizRapid, FreeCAD.Units.Velocity)
|
||||
if hasattr(job.SetupSheet, "VertRapid"):
|
||||
VERTRAPID = Units.Quantity(job.SetupSheet.HorizRapid, FreeCAD.Units.Velocity)
|
||||
|
||||
# do the pre_op
|
||||
if OUTPUT_COMMENTS:
|
||||
gcode += linenumber() + "(begin operation: %s)\n" % obj.Label
|
||||
gcode += linenumber() + "(machine: %s, %s)\n" % (myMachine, UNIT_SPEED_FORMAT)
|
||||
gcode += linenumber() + "(machine: %s, %s)\n" % (MACHINE_NAME, UNIT_SPEED_FORMAT)
|
||||
for line in PRE_OPERATION.splitlines(True):
|
||||
gcode += linenumber() + line
|
||||
|
||||
|
||||
@@ -20,15 +20,14 @@
|
||||
#* *
|
||||
#***************************************************************************
|
||||
|
||||
# reload in python console:
|
||||
# import generic_post
|
||||
# reload(generic_post)
|
||||
# 03-24-2021 Sliptonic: I've removed teh PathUtils import and job lookup
|
||||
# post processors shouldn't be reaching back to the job. This can cause a
|
||||
# proxy error.
|
||||
|
||||
import FreeCAD
|
||||
import argparse
|
||||
import time
|
||||
from PathScripts import PostUtils
|
||||
from PathScripts import PathUtils
|
||||
import math
|
||||
|
||||
TOOLTIP = '''Post processor for Maho M 600E mill
|
||||
@@ -232,16 +231,17 @@ def processArguments(argstring):
|
||||
SHOW_EDITOR = False
|
||||
|
||||
def mkHeader(selection):
|
||||
job = PathUtils.findParentJob(selection[0])
|
||||
# job = PathUtils.findParentJob(selection[0])
|
||||
# this is within a function, because otherwise filename and time don't change when changing the FreeCAD project
|
||||
# now = datetime.datetime.now()
|
||||
now = time.strftime("%Y-%m-%d %H:%M")
|
||||
originfile = FreeCAD.ActiveDocument.FileName
|
||||
headerNoNumber = "%PM\n" # this line gets no linenumber
|
||||
if hasattr(job, "Description"):
|
||||
description = job.Description
|
||||
else:
|
||||
description = ""
|
||||
# if hasattr(job, "Description"):
|
||||
# description = job.Description
|
||||
# else:
|
||||
# description = ""
|
||||
description = ""
|
||||
# this line gets no linenumber, it is already a specially numbered
|
||||
headerNoNumber += "N9XXX (" + description + ", " + now + ")\n"
|
||||
header = ""
|
||||
|
||||
@@ -52,7 +52,7 @@ class TestPathDeburr(PathTestUtils.PathTestBase):
|
||||
self.assertFalse(info)
|
||||
|
||||
def test01(self):
|
||||
'''Verify chamfer depth and offset for a 90° v-bit.'''
|
||||
'''Verify chamfer depth and offset for a 90 deg v-bit.'''
|
||||
tool = Path.Tool()
|
||||
tool.FlatRadius = 0
|
||||
tool.CuttingEdgeAngle = 90
|
||||
@@ -68,7 +68,7 @@ class TestPathDeburr(PathTestUtils.PathTestBase):
|
||||
self.assertFalse(info)
|
||||
|
||||
def test02(self):
|
||||
'''Verify chamfer depth and offset for a 90° v-bit with non 0 flat radius.'''
|
||||
'''Verify chamfer depth and offset for a 90 deg v-bit with non 0 flat radius.'''
|
||||
tool = Path.Tool()
|
||||
tool.FlatRadius = 0.3
|
||||
tool.CuttingEdgeAngle = 90
|
||||
@@ -84,7 +84,7 @@ class TestPathDeburr(PathTestUtils.PathTestBase):
|
||||
self.assertFalse(info)
|
||||
|
||||
def test03(self):
|
||||
'''Verify chamfer depth and offset for a 60° v-bit with non 0 flat radius.'''
|
||||
'''Verify chamfer depth and offset for a 60 deg v-bit with non 0 flat radius.'''
|
||||
tool = Path.Tool()
|
||||
tool.FlatRadius = 10
|
||||
tool.CuttingEdgeAngle = 60
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
"CuttingEdgeHeight": "6.3500 mm",
|
||||
"Diameter": "12.3323 mm",
|
||||
"Length": "30.0000 mm",
|
||||
"ShankDiameter": "6.3500 mm"
|
||||
"TipDiameter": "5.0000 mm",
|
||||
"ShankDiameter": "6.3500 mm",
|
||||
"TipDiameter": "5.0000 mm"
|
||||
},
|
||||
"attribute": {}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
#include <pcl/surface/marching_cubes_hoppe.h>
|
||||
#include <pcl/surface/ear_clipping.h>
|
||||
#include <pcl/common/common.h>
|
||||
#include <pcl/common/io.h>
|
||||
#include <boost/random.hpp>
|
||||
#include <boost/math/special_functions/fpclassify.hpp>
|
||||
|
||||
|
||||
@@ -4864,6 +4864,7 @@ void CmdSketcherConstrainRadius::activated(int iMsg)
|
||||
if (geoIdRadiusMap.empty() && externalGeoIdRadiusMap.empty()) {
|
||||
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
|
||||
QObject::tr("Select one or more arcs or circles from the sketch."));
|
||||
return;
|
||||
}
|
||||
|
||||
if(poles && nonpoles) {
|
||||
@@ -4922,28 +4923,20 @@ void CmdSketcherConstrainRadius::activated(int iMsg)
|
||||
|
||||
if(!geoIdRadiusMap.empty())
|
||||
{
|
||||
bool constrainEqual = false;
|
||||
if (geoIdRadiusMap.size() > 1 && constraintCreationMode==Driving) {
|
||||
int ret = QMessageBox::question(Gui::getMainWindow(), QObject::tr("Constrain equal"),
|
||||
QObject::tr("Do you want to share the same radius for all selected elements?"),
|
||||
QMessageBox::Yes, QMessageBox::No, QMessageBox::Cancel);
|
||||
// use an equality constraint
|
||||
if (ret == QMessageBox::Yes) {
|
||||
constrainEqual = true;
|
||||
}
|
||||
else if (ret == QMessageBox::Cancel) {
|
||||
// do nothing
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (constrainEqual) {
|
||||
// Create the one radius constraint now
|
||||
int refGeoId = geoIdRadiusMap.front().first;
|
||||
double radius = geoIdRadiusMap.front().second;
|
||||
|
||||
if(!commandopened)
|
||||
openCommand(QT_TRANSLATE_NOOP("Command", "Add radius constraint"));
|
||||
|
||||
// Add the equality constraints
|
||||
for (std::vector< std::pair<int, double> >::iterator it = geoIdRadiusMap.begin()+1; it != geoIdRadiusMap.end(); ++it) {
|
||||
Gui::cmdAppObjectArgs(selection[0].getObject(),
|
||||
"addConstraint(Sketcher.Constraint('Equal',%d,%d)) ",
|
||||
refGeoId,it->first);
|
||||
}
|
||||
|
||||
if(nonpoles)
|
||||
Gui::cmdAppObjectArgs(selection[0].getObject(), "addConstraint(Sketcher.Constraint('Radius',%d,%f)) ",
|
||||
@@ -4951,13 +4944,6 @@ void CmdSketcherConstrainRadius::activated(int iMsg)
|
||||
else
|
||||
Gui::cmdAppObjectArgs(selection[0].getObject(), "addConstraint(Sketcher.Constraint('Weight',%d,%f)) ",
|
||||
refGeoId,radius);
|
||||
|
||||
// Add the equality constraints
|
||||
for (std::vector< std::pair<int, double> >::iterator it = geoIdRadiusMap.begin()+1; it != geoIdRadiusMap.end(); ++it) {
|
||||
Gui::cmdAppObjectArgs(selection[0].getObject(),
|
||||
"addConstraint(Sketcher.Constraint('Equal',%d,%d)) ",
|
||||
refGeoId,it->first);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Create the radius constraints now
|
||||
@@ -4995,88 +4981,8 @@ void CmdSketcherConstrainRadius::activated(int iMsg)
|
||||
vp->draw(false,false); // Redraw
|
||||
}
|
||||
|
||||
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher");
|
||||
bool show = hGrp->GetBool("ShowDialogOnDistanceConstraint", true);
|
||||
// Ask for the value of the radius immediately
|
||||
if (show && constraintCreationMode==Driving) {
|
||||
QDialog dlg(Gui::getMainWindow());
|
||||
Ui::InsertDatum ui_Datum;
|
||||
ui_Datum.setupUi(&dlg);
|
||||
Base::Quantity init_val;
|
||||
init_val.setValue(geoIdRadiusMap.front().second);
|
||||
|
||||
if(poles) {
|
||||
dlg.setWindowTitle(EditDatumDialog::tr("Change weight"));
|
||||
ui_Datum.label->setText(EditDatumDialog::tr("Weight:"));
|
||||
|
||||
}
|
||||
else{
|
||||
dlg.setWindowTitle(EditDatumDialog::tr("Change radius"));
|
||||
ui_Datum.label->setText(EditDatumDialog::tr("Radius:"));
|
||||
init_val.setUnit(Base::Unit::Length);
|
||||
}
|
||||
|
||||
ui_Datum.labelEdit->setValue(init_val);
|
||||
ui_Datum.labelEdit->selectNumber();
|
||||
if (constrainEqual || geoIdRadiusMap.size() == 1)
|
||||
ui_Datum.labelEdit->bind(Obj->Constraints.createPath(indexConstr));
|
||||
else
|
||||
ui_Datum.name->setDisabled(true);
|
||||
|
||||
if (dlg.exec() == QDialog::Accepted) {
|
||||
Base::Quantity newQuant = ui_Datum.labelEdit->value();
|
||||
double newRadius = newQuant.getValue();
|
||||
|
||||
try {
|
||||
if (constrainEqual || geoIdRadiusMap.size() == 1) {
|
||||
Gui::cmdAppObjectArgs(Obj, "setDatum(%i,App.Units.Quantity('%f %s'))",
|
||||
indexConstr, newRadius, (const char*)newQuant.getUnit().getString().toUtf8());
|
||||
|
||||
QString constraintName = ui_Datum.name->text().trimmed();
|
||||
if (Base::Tools::toStdString(constraintName) != Obj->Constraints[indexConstr]->Name) {
|
||||
std::string escapedstr = Base::Tools::escapedUnicodeFromUtf8(constraintName.toUtf8().constData());
|
||||
Gui::cmdAppObjectArgs(Obj, "renameConstraint(%d, u'%s')",
|
||||
indexConstr, escapedstr.c_str());
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (std::size_t i=0; i<geoIdRadiusMap.size();i++) {
|
||||
Gui::cmdAppObjectArgs(Obj, "setDatum(%i,App.Units.Quantity('%f %s'))",
|
||||
indexConstr+i, newRadius, (const char*)newQuant.getUnit().getString().toUtf8());
|
||||
}
|
||||
}
|
||||
|
||||
commitCommand();
|
||||
|
||||
if (Obj->noRecomputes && Obj->ExpressionEngine.depsAreTouched()) {
|
||||
Obj->ExpressionEngine.execute();
|
||||
Obj->solve();
|
||||
}
|
||||
|
||||
tryAutoRecompute(Obj);
|
||||
|
||||
commitNeeded=false;
|
||||
updateNeeded=false;
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
QMessageBox::critical(qApp->activeWindow(), QObject::tr("Dimensional constraint"), QString::fromUtf8(e.what()));
|
||||
abortCommand();
|
||||
|
||||
tryAutoRecomputeIfNotSolve(Obj); // we have to update the solver after this aborted addition.
|
||||
}
|
||||
}
|
||||
else {
|
||||
// command canceled
|
||||
abortCommand();
|
||||
|
||||
updateNeeded=true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// now dialog was shown so commit the command
|
||||
commitCommand();
|
||||
commitNeeded=false;
|
||||
}
|
||||
finishDistanceConstraint(this, Obj, constraintCreationMode==Driving);
|
||||
|
||||
//updateActive();
|
||||
getSelection().clearSelection();
|
||||
}
|
||||
@@ -5133,7 +5039,6 @@ void CmdSketcherConstrainRadius::applyConstraint(std::vector<SelIdPair> &selSeq,
|
||||
|
||||
const std::vector<Sketcher::Constraint *> &ConStr = Obj->Constraints.getValues();
|
||||
|
||||
int indexConstr = ConStr.size() - 1;
|
||||
bool fixed = isPointOrSegmentFixed(Obj,GeoId);
|
||||
if(fixed || constraintCreationMode==Reference) {
|
||||
Gui::cmdAppObjectArgs(Obj, "setDriving(%i,%s)",
|
||||
@@ -5154,78 +5059,9 @@ void CmdSketcherConstrainRadius::applyConstraint(std::vector<SelIdPair> &selSeq,
|
||||
vp->draw(); // Redraw
|
||||
}
|
||||
|
||||
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher");
|
||||
bool show = hGrp->GetBool("ShowDialogOnDistanceConstraint", true);
|
||||
// Ask for the value of the radius immediately
|
||||
if (show && constraintCreationMode==Driving && !fixed) {
|
||||
QDialog dlg(Gui::getMainWindow());
|
||||
Ui::InsertDatum ui_Datum;
|
||||
ui_Datum.setupUi(&dlg);
|
||||
Base::Quantity init_val;
|
||||
|
||||
if(ispole) {
|
||||
dlg.setWindowTitle(EditDatumDialog::tr("Change weight"));
|
||||
ui_Datum.label->setText(EditDatumDialog::tr("Weight:"));
|
||||
|
||||
}
|
||||
else{
|
||||
dlg.setWindowTitle(EditDatumDialog::tr("Change radius"));
|
||||
ui_Datum.label->setText(EditDatumDialog::tr("Radius:"));
|
||||
init_val.setUnit(Base::Unit::Length);
|
||||
}
|
||||
|
||||
init_val.setValue(radius);
|
||||
|
||||
ui_Datum.labelEdit->setValue(init_val);
|
||||
ui_Datum.labelEdit->selectNumber();
|
||||
ui_Datum.labelEdit->bind(Obj->Constraints.createPath(indexConstr));
|
||||
|
||||
if (dlg.exec() == QDialog::Accepted) {
|
||||
Base::Quantity newQuant = ui_Datum.labelEdit->value();
|
||||
double newRadius = newQuant.getValue();
|
||||
|
||||
try {
|
||||
Gui::cmdAppObjectArgs(Obj, "setDatum(%i,App.Units.Quantity('%f %s'))",
|
||||
indexConstr, newRadius, (const char*)newQuant.getUnit().getString().toUtf8());
|
||||
|
||||
QString constraintName = ui_Datum.name->text().trimmed();
|
||||
if (Base::Tools::toStdString(constraintName) != Obj->Constraints[indexConstr]->Name) {
|
||||
std::string escapedstr = Base::Tools::escapedUnicodeFromUtf8(constraintName.toUtf8().constData());
|
||||
Gui::cmdAppObjectArgs(Obj, "renameConstraint(%d, u'%s')",
|
||||
indexConstr, escapedstr.c_str());
|
||||
}
|
||||
|
||||
commitCommand();
|
||||
|
||||
if (Obj->noRecomputes && Obj->ExpressionEngine.depsAreTouched()) {
|
||||
Obj->ExpressionEngine.execute();
|
||||
Obj->solve();
|
||||
}
|
||||
|
||||
tryAutoRecompute(Obj);
|
||||
|
||||
commitNeeded=false;
|
||||
updateNeeded=false;
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
QMessageBox::critical(qApp->activeWindow(), QObject::tr("Dimensional constraint"), QString::fromUtf8(e.what()));
|
||||
abortCommand();
|
||||
|
||||
tryAutoRecomputeIfNotSolve(Obj); // we have to update the solver after this aborted addition.
|
||||
}
|
||||
}
|
||||
else {
|
||||
// command canceled
|
||||
abortCommand();
|
||||
|
||||
updateNeeded=true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// now dialog was shown so commit the command
|
||||
commitCommand();
|
||||
commitNeeded=false;
|
||||
}
|
||||
if(!fixed)
|
||||
finishDistanceConstraint(this, Obj, constraintCreationMode==Driving);
|
||||
|
||||
//updateActive();
|
||||
getSelection().clearSelection();
|
||||
|
||||
@@ -5371,6 +5207,7 @@ void CmdSketcherConstrainDiameter::activated(int iMsg)
|
||||
if (geoIdDiameterMap.empty() && externalGeoIdDiameterMap.empty()) {
|
||||
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
|
||||
QObject::tr("Select one or more arcs or circles from the sketch."));
|
||||
return;
|
||||
}
|
||||
|
||||
bool commitNeeded=false;
|
||||
@@ -5417,35 +5254,20 @@ void CmdSketcherConstrainDiameter::activated(int iMsg)
|
||||
|
||||
if(!geoIdDiameterMap.empty())
|
||||
{
|
||||
bool constrainEqual = false;
|
||||
if (geoIdDiameterMap.size() > 1 && constraintCreationMode==Driving) {
|
||||
int ret = QMessageBox::question(Gui::getMainWindow(), QObject::tr("Constrain equal"),
|
||||
QObject::tr("Do you want to share the same diameter for all selected elements?"),
|
||||
QMessageBox::Yes, QMessageBox::No, QMessageBox::Cancel);
|
||||
// use an equality constraint
|
||||
if (ret == QMessageBox::Yes) {
|
||||
constrainEqual = true;
|
||||
}
|
||||
else if (ret == QMessageBox::Cancel) {
|
||||
// do nothing
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (constrainEqual) {
|
||||
// Create the one radius constraint now
|
||||
int refGeoId = geoIdDiameterMap.front().first;
|
||||
double diameter = geoIdDiameterMap.front().second;
|
||||
|
||||
if(!commandopened)
|
||||
openCommand(QT_TRANSLATE_NOOP("Command", "Add diameter constraint"));
|
||||
|
||||
Gui::cmdAppObjectArgs(Obj, "addConstraint(Sketcher.Constraint('Diameter',%d,%f)) ", refGeoId,diameter);
|
||||
|
||||
|
||||
// Add the equality constraints
|
||||
for (std::vector< std::pair<int, double> >::iterator it = geoIdDiameterMap.begin()+1; it != geoIdDiameterMap.end(); ++it) {
|
||||
Gui::cmdAppObjectArgs(Obj, "addConstraint(Sketcher.Constraint('Equal',%d,%d)) ", refGeoId,it->first);
|
||||
}
|
||||
|
||||
Gui::cmdAppObjectArgs(Obj, "addConstraint(Sketcher.Constraint('Diameter',%d,%f)) ", refGeoId,diameter);
|
||||
}
|
||||
else {
|
||||
// Create the diameter constraints now
|
||||
@@ -5482,80 +5304,8 @@ void CmdSketcherConstrainDiameter::activated(int iMsg)
|
||||
}
|
||||
vp->draw(false,false); // Redraw
|
||||
}
|
||||
|
||||
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher");
|
||||
bool show = hGrp->GetBool("ShowDialogOnDistanceConstraint", true);
|
||||
// Ask for the value of the diameter immediately
|
||||
if (show && constraintCreationMode==Driving) {
|
||||
QDialog dlg(Gui::getMainWindow());
|
||||
Ui::InsertDatum ui_Datum;
|
||||
ui_Datum.setupUi(&dlg);
|
||||
dlg.setWindowTitle(EditDatumDialog::tr("Change diameter"));
|
||||
ui_Datum.label->setText(EditDatumDialog::tr("Diameter:"));
|
||||
Base::Quantity init_val;
|
||||
init_val.setUnit(Base::Unit::Length);
|
||||
init_val.setValue(geoIdDiameterMap.front().second);
|
||||
|
||||
ui_Datum.labelEdit->setValue(init_val);
|
||||
ui_Datum.labelEdit->selectNumber();
|
||||
if (constrainEqual || geoIdDiameterMap.size() == 1)
|
||||
ui_Datum.labelEdit->bind(Obj->Constraints.createPath(indexConstr));
|
||||
else
|
||||
ui_Datum.name->setDisabled(true);
|
||||
|
||||
if (dlg.exec() == QDialog::Accepted) {
|
||||
Base::Quantity newQuant = ui_Datum.labelEdit->value();
|
||||
double newDiameter = newQuant.getValue();
|
||||
|
||||
try {
|
||||
if (constrainEqual || geoIdDiameterMap.size() == 1) {
|
||||
Gui::cmdAppObjectArgs(Obj, "setDatum(%i,App.Units.Quantity('%f %s'))",
|
||||
indexConstr, newDiameter, (const char*)newQuant.getUnit().getString().toUtf8());
|
||||
|
||||
QString constraintName = ui_Datum.name->text().trimmed();
|
||||
if (Base::Tools::toStdString(constraintName) != Obj->Constraints[indexConstr]->Name) {
|
||||
std::string escapedstr = Base::Tools::escapedUnicodeFromUtf8(constraintName.toUtf8().constData());
|
||||
Gui::cmdAppObjectArgs(Obj, "renameConstraint(%d, u'%s')", indexConstr, escapedstr.c_str());
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (std::size_t i=0; i<geoIdDiameterMap.size();i++) {
|
||||
Gui::cmdAppObjectArgs(Obj, "setDatum(%i,App.Units.Quantity('%f %s'))",
|
||||
indexConstr+i, newDiameter, (const char*)newQuant.getUnit().getString().toUtf8());
|
||||
}
|
||||
}
|
||||
|
||||
commitCommand();
|
||||
|
||||
if (Obj->noRecomputes && Obj->ExpressionEngine.depsAreTouched()) {
|
||||
Obj->ExpressionEngine.execute();
|
||||
Obj->solve();
|
||||
}
|
||||
|
||||
tryAutoRecompute(Obj);
|
||||
|
||||
commitNeeded=false;
|
||||
updateNeeded=false;
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
QMessageBox::critical(qApp->activeWindow(), QObject::tr("Dimensional constraint"), QString::fromUtf8(e.what()));
|
||||
abortCommand();
|
||||
|
||||
tryAutoRecomputeIfNotSolve(Obj); // we have to update the solver after this aborted addition.
|
||||
}
|
||||
}
|
||||
else {
|
||||
// command canceled
|
||||
abortCommand();
|
||||
|
||||
updateNeeded=true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// now dialog was shown so commit the command
|
||||
commitCommand();
|
||||
commitNeeded=false;
|
||||
}
|
||||
finishDistanceConstraint(this, Obj, constraintCreationMode==Driving);
|
||||
|
||||
//updateActive();
|
||||
getSelection().clearSelection();
|
||||
}
|
||||
@@ -5611,7 +5361,6 @@ void CmdSketcherConstrainDiameter::applyConstraint(std::vector<SelIdPair> &selSe
|
||||
|
||||
const std::vector<Sketcher::Constraint *> &ConStr = Obj->Constraints.getValues();
|
||||
|
||||
int indexConstr = ConStr.size() - 1;
|
||||
bool fixed = isPointOrSegmentFixed(Obj,GeoId);
|
||||
if(fixed || constraintCreationMode==Reference) {
|
||||
Gui::cmdAppObjectArgs(Obj, "setDriving(%i,%s)", ConStr.size()-1, "False");
|
||||
@@ -5629,69 +5378,9 @@ void CmdSketcherConstrainDiameter::applyConstraint(std::vector<SelIdPair> &selSe
|
||||
constr->LabelDistance = 2. * sf;
|
||||
vp->draw(); // Redraw
|
||||
}
|
||||
|
||||
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher");
|
||||
bool show = hGrp->GetBool("ShowDialogOnDistanceConstraint", true);
|
||||
// Ask for the value of the diameter immediately
|
||||
if (show && constraintCreationMode==Driving && !fixed) {
|
||||
QDialog dlg(Gui::getMainWindow());
|
||||
Ui::InsertDatum ui_Datum;
|
||||
ui_Datum.setupUi(&dlg);
|
||||
dlg.setWindowTitle(EditDatumDialog::tr("Change diameter"));
|
||||
ui_Datum.label->setText(EditDatumDialog::tr("Diameter:"));
|
||||
Base::Quantity init_val;
|
||||
init_val.setUnit(Base::Unit::Length);
|
||||
init_val.setValue(diameter);
|
||||
|
||||
ui_Datum.labelEdit->setValue(init_val);
|
||||
ui_Datum.labelEdit->selectNumber();
|
||||
ui_Datum.labelEdit->bind(Obj->Constraints.createPath(indexConstr));
|
||||
|
||||
if (dlg.exec() == QDialog::Accepted) {
|
||||
Base::Quantity newQuant = ui_Datum.labelEdit->value();
|
||||
double newDiameter = newQuant.getValue();
|
||||
|
||||
try {
|
||||
Gui::cmdAppObjectArgs(Obj, "setDatum(%i,App.Units.Quantity('%f %s'))",
|
||||
indexConstr, newDiameter, (const char*)newQuant.getUnit().getString().toUtf8());
|
||||
|
||||
QString constraintName = ui_Datum.name->text().trimmed();
|
||||
if (Base::Tools::toStdString(constraintName) != Obj->Constraints[indexConstr]->Name) {
|
||||
std::string escapedstr = Base::Tools::escapedUnicodeFromUtf8(constraintName.toUtf8().constData());
|
||||
Gui::cmdAppObjectArgs(Obj, "renameConstraint(%d, u'%s')", indexConstr, escapedstr.c_str());
|
||||
}
|
||||
|
||||
commitCommand();
|
||||
|
||||
if (Obj->noRecomputes && Obj->ExpressionEngine.depsAreTouched()) {
|
||||
Obj->ExpressionEngine.execute();
|
||||
Obj->solve();
|
||||
}
|
||||
|
||||
tryAutoRecompute(Obj);
|
||||
|
||||
commitNeeded=false;
|
||||
updateNeeded=false;
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
QMessageBox::critical(qApp->activeWindow(), QObject::tr("Dimensional constraint"), QString::fromUtf8(e.what()));
|
||||
abortCommand();
|
||||
|
||||
tryAutoRecomputeIfNotSolve(Obj); // we have to update the solver after this aborted addition.
|
||||
}
|
||||
}
|
||||
else {
|
||||
// command canceled
|
||||
abortCommand();
|
||||
|
||||
updateNeeded=true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// now dialog was shown so commit the command
|
||||
commitCommand();
|
||||
commitNeeded=false;
|
||||
}
|
||||
if(!fixed)
|
||||
finishDistanceConstraint(this, Obj, constraintCreationMode==Driving);
|
||||
|
||||
//updateActive();
|
||||
getSelection().clearSelection();
|
||||
|
||||
@@ -7121,13 +6810,13 @@ void CmdSketcherConstrainInternalAlignment::activated(int iMsg)
|
||||
|
||||
const Part::Geometry *geo = Obj->getGeometry(GeoId);
|
||||
|
||||
if (geo->getTypeId() == Part::GeomPoint::getClassTypeId())
|
||||
if (geo && geo->getTypeId() == Part::GeomPoint::getClassTypeId())
|
||||
pointids.push_back(GeoId);
|
||||
else if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId())
|
||||
else if (geo && geo->getTypeId() == Part::GeomLineSegment::getClassTypeId())
|
||||
lineids.push_back(GeoId);
|
||||
else if (geo->getTypeId() == Part::GeomEllipse::getClassTypeId())
|
||||
else if (geo && geo->getTypeId() == Part::GeomEllipse::getClassTypeId())
|
||||
ellipseids.push_back(GeoId);
|
||||
else if (geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId())
|
||||
else if (geo && geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId())
|
||||
arcsofellipseids.push_back(GeoId);
|
||||
else {
|
||||
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
|
||||
|
||||
@@ -106,6 +106,9 @@ Base::Vector2d GetCircleCenter (const Base::Vector2d &p1, const Base::Vector2d &
|
||||
double vv = v*v;
|
||||
double ww = w*w;
|
||||
|
||||
if (uu * vv * ww == 0)
|
||||
THROWM(Base::ValueError,"Two points are coincident");
|
||||
|
||||
double uv = -(u*v);
|
||||
double vw = -(v*w);
|
||||
double uw = -(u*w);
|
||||
@@ -507,7 +510,8 @@ public:
|
||||
"conList.append(Sketcher.Constraint('Horizontal',%i))\n"
|
||||
"conList.append(Sketcher.Constraint('Vertical',%i))\n"
|
||||
"conList.append(Sketcher.Constraint('Vertical',%i))\n"
|
||||
"%s.addConstraint(conList)\n",
|
||||
"%s.addConstraint(conList)\n"
|
||||
"del geoList, conList\n",
|
||||
EditCurve[0].x,EditCurve[0].y,EditCurve[1].x,EditCurve[1].y, // line 1
|
||||
EditCurve[1].x,EditCurve[1].y,EditCurve[2].x,EditCurve[2].y, // line 2
|
||||
EditCurve[2].x,EditCurve[2].y,EditCurve[3].x,EditCurve[3].y, // line 3
|
||||
@@ -4251,6 +4255,7 @@ public:
|
||||
}
|
||||
|
||||
cstream << Gui::Command::getObjectCmd(sketchgui->getObject()) << ".addConstraint(conList)\n";
|
||||
cstream << "del conList\n";
|
||||
|
||||
Gui::Command::doCommand(Gui::Command::Doc, cstream.str().c_str());
|
||||
|
||||
@@ -6366,7 +6371,8 @@ public:
|
||||
"conList.append(Sketcher.Constraint('Tangent',%i,2,%i,2))\n"
|
||||
"conList.append(Sketcher.Constraint('%s',%i))\n"
|
||||
"conList.append(Sketcher.Constraint('Equal',%i,%i))\n"
|
||||
"%s.addConstraint(conList)\n",
|
||||
"%s.addConstraint(conList)\n"
|
||||
"del geoList, conList\n",
|
||||
StartPos.x,StartPos.y, // center of the arc1
|
||||
fabs(r), // radius arc1
|
||||
start,end, // start and end angle of arc1
|
||||
|
||||
@@ -375,7 +375,7 @@ public:
|
||||
class ExpressionDelegate : public QStyledItemDelegate
|
||||
{
|
||||
public:
|
||||
ExpressionDelegate(QListWidget * _view) : view(_view) { }
|
||||
ExpressionDelegate(QListWidget* _view) : QStyledItemDelegate(_view), view(_view) { }
|
||||
protected:
|
||||
QPixmap getIcon(const char* name, const QSize& size) const
|
||||
{
|
||||
|
||||
@@ -266,9 +266,6 @@ void TaskSketcherGeneral::onChangedSketchView(const Gui::ViewProvider& vp,
|
||||
QSignalBlocker block(widget);
|
||||
widget->checkGridView(sketchView->ShowGrid.getValue());
|
||||
widget->enableGridSettings(sketchView->ShowGrid.getValue());
|
||||
if (sketchView->ShowGrid.getValue()) {
|
||||
sketchView->createGrid();
|
||||
}
|
||||
}
|
||||
else if (&sketchView->GridSize == &prop) {
|
||||
QSignalBlocker block(widget);
|
||||
@@ -295,7 +292,6 @@ void TaskSketcherGeneral::onToggleGridView(bool on)
|
||||
Base::ConnectionBlocker block(changedSketchView);
|
||||
sketchView->ShowGrid.setValue(on);
|
||||
widget->enableGridSettings(on);
|
||||
if (on) sketchView->createGrid();
|
||||
}
|
||||
|
||||
void TaskSketcherGeneral::onSetGridSize(double val)
|
||||
|
||||
@@ -6275,6 +6275,7 @@ bool ViewProviderSketch::setEdit(int ModNum)
|
||||
" tv.show([ref[0] for ref in ActiveSketch.ExternalGeometry])\n"
|
||||
"tv.hide(ActiveSketch)\n"
|
||||
"del(tv)\n"
|
||||
"del(ActiveSketch)\n"
|
||||
).arg(QString::fromLatin1(getDocument()->getDocument()->getName()),
|
||||
QString::fromLatin1(getSketchObject()->getNameInDocument()),
|
||||
QString::fromLatin1(Gui::Command::getObjectCmd(editObj).c_str()),
|
||||
@@ -6790,6 +6791,7 @@ void ViewProviderSketch::unsetEdit(int ModNum)
|
||||
" tv.restore()\n"
|
||||
"ActiveSketch.ViewObject.TempoVis = None\n"
|
||||
"del(tv)\n"
|
||||
"del(ActiveSketch)\n"
|
||||
).arg(QString::fromLatin1(getDocument()->getDocument()->getName())).arg(
|
||||
QString::fromLatin1(getSketchObject()->getNameInDocument()));
|
||||
QByteArray cmdstr_bytearray = cmdstr.toLatin1();
|
||||
|
||||
@@ -391,14 +391,16 @@ void PropertySheet::pasteCells(XMLReader &reader, const CellAddress &addr) {
|
||||
roffset = addr.row() - from.row();
|
||||
coffset = addr.col() - from.col();
|
||||
}else
|
||||
range.next();
|
||||
if (!range.next())
|
||||
break;
|
||||
while(src!=*range) {
|
||||
CellAddress dst(*range);
|
||||
dst.setRow(dst.row()+roffset);
|
||||
dst.setCol(dst.col()+coffset);
|
||||
owner->clear(dst);
|
||||
owner->cellUpdated(dst);
|
||||
range.next();
|
||||
if (!range.next())
|
||||
break;
|
||||
}
|
||||
CellAddress dst(src.row()+roffset, src.col()+coffset);
|
||||
auto cell = owner->getNewCell(dst);
|
||||
@@ -537,12 +539,11 @@ void PropertySheet::setAlias(CellAddress address, const std::string &alias)
|
||||
|
||||
const Cell * aliasedCell = getValueFromAlias(alias);
|
||||
Cell * cell = nonNullCellAt(address);
|
||||
assert(cell != 0);
|
||||
|
||||
if (aliasedCell != 0 && cell != aliasedCell)
|
||||
throw Base::ValueError("Alias already defined.");
|
||||
|
||||
assert(cell != 0);
|
||||
|
||||
/* Mark cells depending on this cell dirty; they need to be resolved when an alias changes or disappears */
|
||||
std::string fullName = owner->getFullName() + "." + address.toString();
|
||||
|
||||
|
||||
@@ -47,5 +47,5 @@ INSTALL(
|
||||
FILES
|
||||
${Start_Tests}
|
||||
DESTINATION
|
||||
Mod/Start/testStart
|
||||
Mod/Start/TestStart
|
||||
)
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
import six
|
||||
import sys,os,FreeCAD,FreeCADGui,tempfile,time,zipfile,re
|
||||
import urllib.parse
|
||||
from . import TranslationTexts
|
||||
from PySide import QtCore,QtGui
|
||||
|
||||
@@ -248,7 +249,7 @@ def buildCard(filename,method,arg=None):
|
||||
infostring += "\n\n" + encode(finfo[5])
|
||||
if size:
|
||||
result += '<li class="icon">'
|
||||
result += '<a href="'+method+arg+'" title="'+infostring+'">'
|
||||
result += '<a href="'+method+urllib.parse.quote(arg)+'" title="'+infostring+'">'
|
||||
result += '<img src="file:///'+image.replace('\\','/')+'" alt="'+encode(basename)+'">'
|
||||
result += '<div class="caption">'
|
||||
result += '<h4>'+encode(basename)+'</h4>'
|
||||
@@ -415,15 +416,18 @@ def handle():
|
||||
for cfolder in cfolders.split(";;"): # allow several paths separated by ;;
|
||||
if not os.path.isdir(cfolder):
|
||||
cfolder = os.path.dirname(cfolder)
|
||||
SECTION_CUSTOM += encode("<h2>"+os.path.basename(os.path.normpath(cfolder))+"</h2>")
|
||||
SECTION_CUSTOM += "<ul>"
|
||||
for basename in os.listdir(cfolder):
|
||||
filename = os.path.join(cfolder,basename)
|
||||
SECTION_CUSTOM += encode(buildCard(filename,method="LoadCustom.py?filename="+str(dn)+"_"))
|
||||
SECTION_CUSTOM += "</ul>"
|
||||
# hide the custom section tooltip if custom section is set (users know about it if they enabled it)
|
||||
HTML = HTML.replace("id=\"customtip\"","id=\"customtip\" style=\"display:none;\"")
|
||||
dn += 1
|
||||
if not os.path.exists(cfolder):
|
||||
FreeCAD.Console.PrintWarning("Custom folder not found: %s" % cfolder)
|
||||
else:
|
||||
SECTION_CUSTOM += encode("<h2>"+os.path.basename(os.path.normpath(cfolder))+"</h2>")
|
||||
SECTION_CUSTOM += "<ul>"
|
||||
for basename in os.listdir(cfolder):
|
||||
filename = os.path.join(cfolder,basename)
|
||||
SECTION_CUSTOM += encode(buildCard(filename,method="LoadCustom.py?filename="+str(dn)+"_"))
|
||||
SECTION_CUSTOM += "</ul>"
|
||||
# hide the custom section tooltip if custom section is set (users know about it if they enabled it)
|
||||
HTML = HTML.replace("id=\"customtip\" class","id=\"customtip\" style=\"display:none;\" class")
|
||||
dn += 1
|
||||
HTML = HTML.replace("SECTION_CUSTOM",SECTION_CUSTOM)
|
||||
|
||||
# build IMAGE_SRC paths
|
||||
|
||||
@@ -324,7 +324,10 @@ short DrawViewPart::mustExecute() const
|
||||
SeamHidden.isTouched() ||
|
||||
IsoHidden.isTouched() ||
|
||||
IsoCount.isTouched() ||
|
||||
CoarseView.isTouched());
|
||||
CoarseView.isTouched() ||
|
||||
CosmeticVertexes.isTouched() ||
|
||||
CosmeticEdges.isTouched() ||
|
||||
CenterLines.isTouched());
|
||||
}
|
||||
|
||||
if (result) {
|
||||
|
||||
@@ -348,6 +348,8 @@ void execMidpoints(Gui::Command* cmd)
|
||||
return;
|
||||
}
|
||||
|
||||
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Add Midpont Vertices"));
|
||||
|
||||
const std::vector<TechDraw::BaseGeom*> edges = dvp->getEdgeGeometry();
|
||||
double scale = dvp->getScale();
|
||||
for (auto& s: selectedEdges) {
|
||||
@@ -357,6 +359,9 @@ void execMidpoints(Gui::Command* cmd)
|
||||
mid = DrawUtil::invertY(mid);
|
||||
dvp->addCosmeticVertex(mid / scale);
|
||||
}
|
||||
|
||||
Gui::Command::commitCommand();
|
||||
|
||||
dvp->recomputeFeature();
|
||||
}
|
||||
|
||||
@@ -371,6 +376,8 @@ void execQuadrants(Gui::Command* cmd)
|
||||
return;
|
||||
}
|
||||
|
||||
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Add Quadrant Vertices"));
|
||||
|
||||
const std::vector<TechDraw::BaseGeom*> edges = dvp->getEdgeGeometry();
|
||||
double scale = dvp->getScale();
|
||||
for (auto& s: selectedEdges) {
|
||||
@@ -382,6 +389,9 @@ void execQuadrants(Gui::Command* cmd)
|
||||
dvp->addCosmeticVertex(iq / scale);
|
||||
}
|
||||
}
|
||||
|
||||
Gui::Command::commitCommand();
|
||||
|
||||
dvp->recomputeFeature();
|
||||
}
|
||||
|
||||
|
||||
@@ -161,11 +161,15 @@ void TaskCosVertex::updateUi(void)
|
||||
|
||||
void TaskCosVertex::addCosVertex(QPointF qPos)
|
||||
{
|
||||
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Add Cosmetic Vertex"));
|
||||
|
||||
// Base::Console().Message("TCV::addCosVertex(%s)\n", TechDraw::DrawUtil::formatVector(qPos).c_str());
|
||||
Base::Vector3d pos(qPos.x(), -qPos.y());
|
||||
// int idx =
|
||||
(void) m_baseFeat->addCosmeticVertex(pos);
|
||||
m_baseFeat->requestPaint();
|
||||
|
||||
Gui::Command::commitCommand();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -203,6 +203,8 @@ void TaskCosmeticLine::setUiEdit()
|
||||
//******************************************************************************
|
||||
void TaskCosmeticLine::createCosmeticLine(void)
|
||||
{
|
||||
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Create Cosmetic Line"));
|
||||
|
||||
double x = ui->qsbx1->value().getValue();
|
||||
double y = ui->qsby1->value().getValue();
|
||||
double z = ui->qsbz1->value().getValue();
|
||||
@@ -227,6 +229,8 @@ void TaskCosmeticLine::createCosmeticLine(void)
|
||||
|
||||
m_tag = m_partFeat->addCosmeticEdge(p0, p1);
|
||||
m_ce = m_partFeat->getCosmeticEdge(m_tag);
|
||||
|
||||
Gui::Command::commitCommand();
|
||||
}
|
||||
|
||||
void TaskCosmeticLine::updateCosmeticLine(void)
|
||||
|
||||
@@ -191,6 +191,10 @@ bool ViewProviderTemplate::onDelete(const std::vector<std::string> &)
|
||||
// get the page
|
||||
auto page = getTemplate()->getParentPage();
|
||||
|
||||
// If no parent page is given then just go ahead
|
||||
if (!page)
|
||||
return true;
|
||||
|
||||
// generate dialog
|
||||
QString bodyMessage;
|
||||
QTextStream bodyMessageStream(&bodyMessage);
|
||||
|
||||
@@ -1307,7 +1307,7 @@ class DocumentFileIncludeCases(unittest.TestCase):
|
||||
# copy file from L5 which is in the same directory
|
||||
L7 = doc2.addObject("App::DocumentObjectFileIncluded","FileObject3")
|
||||
L7.File = (L5.File,"Copy.txt")
|
||||
self.failUnless(os.path.exists(L5.File))
|
||||
self.failUnless(os.path.exists(L7.File))
|
||||
FreeCAD.closeDocument("Doc2")
|
||||
|
||||
|
||||
|
||||
@@ -125,9 +125,10 @@ class UnitBasicCases(unittest.TestCase):
|
||||
try:
|
||||
q2 = FreeCAD.Units.Quantity(t[0])
|
||||
if math.fabs(q1.Value - q2.Value) > 0.01:
|
||||
print (q1, " : ", q2, " : ", t, " : ", i, " : ", val)
|
||||
print (u" {} : {} : {} : {} : {}".format(q1,q2, t, i, val).encode("utf-8").strip())
|
||||
except Exception as e:
|
||||
print ("{}: {}".format(str(e), t[0]))
|
||||
s = "{}: {}".format(e, t[0])
|
||||
print (u" ".join(e).encode("utf-8").strip())
|
||||
|
||||
def testVoltage(self):
|
||||
q1 = FreeCAD.Units.Quantity("1e20 V")
|
||||
|
||||
@@ -239,6 +239,7 @@ Py::Object BrowserViewPy::setHtml(const Py::Tuple& args)
|
||||
WebView::WebView(QWidget *parent)
|
||||
: QWEBVIEW(parent)
|
||||
{
|
||||
#ifdef QTWEBKIT
|
||||
// Increase html font size for high DPI displays
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
QRect mainScreenSize = QApplication::primaryScreen()->geometry();
|
||||
@@ -248,6 +249,7 @@ WebView::WebView(QWidget *parent)
|
||||
if (mainScreenSize.width() > 1920){
|
||||
setTextSizeMultiplier (mainScreenSize.width()/1920.0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef QTWEBENGINE
|
||||
|
||||
@@ -20,14 +20,14 @@ To build the installer you can do the following:
|
||||
(You can alternatively get nsProcess from https://nsis.sourceforge.io/NsProcess_plugin)
|
||||
7. Copy all FreeCAD files to the folder "~\FreeCAD"
|
||||
e.g. "C:\FreeCAD\Installer\FreeCAD"
|
||||
8. If you use a version of FreeCAD that was compiled using another MSVC version than MSVC 2017,
|
||||
8. If you use a version of FreeCAD that was compiled using another MSVC version than MSVC 2019,
|
||||
copy its distributable DLLs to the folder FILES_DEPS (see step 3).
|
||||
9. Right-click on the file FreeCAD-installer.nsi and choose "Compile NSIS script"
|
||||
to compile the installer.
|
||||
10. The folder ~\MSVCRedist contains already all MSVC 2017 x64 redistributable DLLs necessary
|
||||
for FreeCAD 0.19dev. If another MSVC version was used to compile FreeCAD, replace the DLLs by
|
||||
10. The folder ~\MSVCRedist contains already all MSVC 2019 x64 redistributable DLLs necessary
|
||||
for FreeCAD 0.19. If another MSVC version was used to compile FreeCAD, replace the DLLs by
|
||||
the ones of the used MSVC. (They are usually available in the folder
|
||||
C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Redist\MSVC)
|
||||
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Redist\MSVC)
|
||||
|
||||
For test builds of the installer you can turn off the compression. This speeds up
|
||||
the build time for the installer a lot but increases its file size. The compression
|
||||
|
||||
@@ -17,19 +17,19 @@ SetCompressor /SOLID lzma
|
||||
|
||||
!define APP_VERSION_MAJOR 0
|
||||
!define APP_VERSION_MINOR 19
|
||||
!define APP_VERSION_REVISION 0
|
||||
!define APP_VERSION_EMERGENCY "rev18731" # use "1" for an emergency release of FreeCAD otherwise ""
|
||||
!define APP_VERSION_REVISION 3
|
||||
!define APP_VERSION_EMERGENCY "" # use "1" for an emergency release of FreeCAD otherwise ""
|
||||
# alternatively you can use APP_VERSION_EMERGENCY for a custom suffix of the version number
|
||||
!define APP_EMERGENCY_DOT "" # use "." for an emergency release of FreeCAD otherwise ""
|
||||
!define APP_VERSION_BUILD 1 # Start with 1 for the installer releases of each version
|
||||
|
||||
!define APP_VERSION "${APP_VERSION_MAJOR}.${APP_VERSION_MINOR}.${APP_VERSION_REVISION}${APP_EMERGENCY_DOT}${APP_VERSION_EMERGENCY}" # Version to display
|
||||
|
||||
!define COPYRIGHT_YEAR 2020
|
||||
!define COPYRIGHT_YEAR 2021
|
||||
|
||||
#--------------------------------
|
||||
# Installer file name
|
||||
# Typical names for the release are "FreeCAD-018-Installer-1.exe" etc.
|
||||
# Typical names for the release are "FreeCAD-019-Installer-1.exe" etc.
|
||||
|
||||
!define ExeFile "${APP_NAME}-${APP_VERSION_MAJOR}${APP_VERSION_MINOR}${APP_VERSION_REVISION}${APP_VERSION_EMERGENCY}-Installer-${APP_VERSION_BUILD}.exe"
|
||||
|
||||
@@ -43,6 +43,6 @@ SetCompressor /SOLID lzma
|
||||
# File locations
|
||||
# !!! you need to adjust them to the folders in your Windows system !!!
|
||||
|
||||
!define FILES_FREECAD "D:\usti\FreeCAD\Installer\FreeCAD"
|
||||
!define FILES_DEPS "D:\usti\FreeCAD\Installer\MSVCRedist"
|
||||
!define FILES_THUMBS "D:\usti\FreeCAD\Installer\thumbnail"
|
||||
!define FILES_FREECAD "G:\FreeCADInst\Installer\FreeCAD"
|
||||
!define FILES_DEPS "G:\FreeCADInst\Installer\MSVCRedist"
|
||||
!define FILES_THUMBS "G:\FreeCADInst\Installer\thumbnail"
|
||||
|
||||
@@ -42,8 +42,14 @@ Configuration and variables of FreeCAD installer
|
||||
!define APP_REGNAME_DOC "${APP_NAME}.Document"
|
||||
|
||||
!define APP_EXT ".FCStd"
|
||||
!define APP_EXT1 ".FCStd1"
|
||||
!define APP_MIME_TYPE "application/x-zip-compressed"
|
||||
|
||||
!define APP_EXT_BAK ".FCBak"
|
||||
!define APP_EXT_MACRO ".FCMacro"
|
||||
!define APP_EXT_MAT ".FCMat"
|
||||
!define APP_EXT_SCRIPT ".FCScript"
|
||||
|
||||
!define APP_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${SETUP_UNINSTALLER_KEY}"
|
||||
|
||||
#--------------------------------
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user