Compare commits
149 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0a49fd05a4 | |||
| 476ecf0919 | |||
| 8eccef1d87 | |||
| 7103dfd1a2 | |||
| ae1b3e0d96 | |||
| c88a1749c7 | |||
| 03f06f794f | |||
| c453ec12e7 | |||
| 2065e5573d | |||
| d257a8a8d6 | |||
| 042066c55e | |||
| 25ead17570 | |||
| e305560dd8 | |||
| 7dfe408686 | |||
| fd6ff10212 | |||
| d549cff781 | |||
| a8f9f1dd42 | |||
| 15b3cf45b1 | |||
| 9af7405d5e | |||
| 992c0ddc64 | |||
| 0dfc4aff74 | |||
| f4defb5c39 | |||
| f0d783b69f | |||
| 186bfff31c | |||
| 03ef59bc4b | |||
| 95d0004742 | |||
| 8489a55067 | |||
| 2eb6d4748e | |||
| b56a4292ae | |||
| 1ffd8d553b | |||
| 1caea909b5 | |||
| d8e6fe8287 | |||
| ad6977f940 | |||
| b1630419fc | |||
| bca9684ec3 | |||
| a73f442f88 | |||
| 88eb350ac0 | |||
| 454d1cbeb3 | |||
| e238e2f257 | |||
| b0ae197937 | |||
| 805fb0df02 | |||
| 0b72f23bfb | |||
| dc2d9ba2f0 | |||
| b4e58cea01 | |||
| 16ee414987 | |||
| a84ff0b567 | |||
| 099a8027d6 | |||
| 9eefd120d1 | |||
| 12974031a9 | |||
| 2982c875b2 | |||
| 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());
|
||||
|
||||
@@ -149,7 +149,7 @@ PyObject* MatrixPy::number_multiply_handler(PyObject *self, PyObject *other)
|
||||
}
|
||||
|
||||
if (PyNumber_Check(other)) {
|
||||
double v = PyFloat_AsDouble(self);
|
||||
double v = PyFloat_AsDouble(other);
|
||||
a.scale(v,v,v);
|
||||
return new MatrixPy(a);
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -1073,26 +1073,29 @@ PyObject* Application::sAddIconPath(PyObject * /*self*/, PyObject *args)
|
||||
PyObject* Application::sAddIcon(PyObject * /*self*/, PyObject *args)
|
||||
{
|
||||
const char *iconName;
|
||||
const char *content;
|
||||
Py_ssize_t size = 0;
|
||||
Py_buffer content;
|
||||
const char *format = "XPM";
|
||||
if (!PyArg_ParseTuple(args, "ss#|s", &iconName,&content,&size,&format))
|
||||
if (!PyArg_ParseTuple(args, "ss*|s", &iconName, &content, &format))
|
||||
return NULL;
|
||||
|
||||
QPixmap icon;
|
||||
if (BitmapFactory().findPixmapInCache(iconName, icon)) {
|
||||
PyErr_SetString(PyExc_AssertionError, "Icon with this name already registered");
|
||||
PyBuffer_Release(&content);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QByteArray ary(content,size);
|
||||
const char* contentStr = static_cast<const char*>(content.buf);
|
||||
QByteArray ary(contentStr, content.len);
|
||||
icon.loadFromData(ary, format);
|
||||
|
||||
if (icon.isNull()){
|
||||
QString file = QString::fromUtf8(content);
|
||||
QString file = QString::fromUtf8(contentStr, content.len);
|
||||
icon.load(file);
|
||||
}
|
||||
|
||||
PyBuffer_Release(&content);
|
||||
|
||||
if (icon.isNull()) {
|
||||
PyErr_SetString(Base::BaseExceptionFreeCADError, "Invalid icon added to application");
|
||||
return NULL;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -1304,6 +1304,8 @@ void MainWindow::delayedStartup()
|
||||
if (hGrp->GetBool("CreateNewDoc", false)) {
|
||||
if (App::GetApplication().getDocuments().size()==0){
|
||||
App::GetApplication().newDocument();
|
||||
Gui::Command::doCommand(Gui::Command::Gui,
|
||||
"Gui.activeDocument().activeView().viewDefaultOrientation()");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -24,7 +24,9 @@
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
# include <QAction>
|
||||
# include <QByteArray>
|
||||
# include <QMenu>
|
||||
# include <qpixmap.h>
|
||||
# include <Inventor/actions/SoSearchAction.h>
|
||||
# include <Inventor/nodes/SoDrawStyle.h>
|
||||
@@ -47,7 +49,9 @@
|
||||
#include <App/DocumentObjectGroup.h>
|
||||
#include <App/DocumentObserver.h>
|
||||
#include <App/Origin.h>
|
||||
#include "ActionFunction.h"
|
||||
#include "Application.h"
|
||||
#include "Command.h"
|
||||
#include "Document.h"
|
||||
#include "Selection.h"
|
||||
#include "MainWindow.h"
|
||||
@@ -256,6 +260,25 @@ void ViewProviderDocumentObject::setShowable(bool enable)
|
||||
}
|
||||
}
|
||||
|
||||
void ViewProviderDocumentObject::startDefaultEditMode()
|
||||
{
|
||||
QString text = QObject::tr("Edit %1").arg(QString::fromUtf8(getObject()->Label.getValue()));
|
||||
Gui::Command::openCommand(text.toUtf8());
|
||||
|
||||
Gui::Document* document = this->getDocument();
|
||||
if (document) {
|
||||
document->setEdit(this, ViewProvider::Default);
|
||||
}
|
||||
}
|
||||
|
||||
void ViewProviderDocumentObject::addDefaultAction(QMenu* menu, const QString& text)
|
||||
{
|
||||
QAction* act = menu->addAction(text);
|
||||
act->setData(QVariant((int)ViewProvider::Default));
|
||||
Gui::ActionFunction* func = new Gui::ActionFunction(menu);
|
||||
func->trigger(act, boost::bind(&ViewProviderDocumentObject::startDefaultEditMode, this));
|
||||
}
|
||||
|
||||
void ViewProviderDocumentObject::setModeSwitch() {
|
||||
if(isShowable())
|
||||
ViewProvider::setModeSwitch();
|
||||
|
||||
@@ -155,6 +155,9 @@ public:
|
||||
void setShowable(bool enable);
|
||||
bool isShowable() const;
|
||||
|
||||
/** Start the edit mode with ViewProvider::Default */
|
||||
void startDefaultEditMode();
|
||||
|
||||
protected:
|
||||
/*! Get the active mdi view of the document this view provider is part of.
|
||||
@note The returned mdi view doesn't need to be a 3d view but can be e.g.
|
||||
@@ -203,6 +206,9 @@ protected:
|
||||
|
||||
virtual void setModeSwitch() override;
|
||||
|
||||
/** Adds a menu item and bind it with \ref startDefaultEditMode(). */
|
||||
void addDefaultAction(QMenu*, const QString&);
|
||||
|
||||
protected:
|
||||
App::DocumentObject *pcObject;
|
||||
Gui::Document* pcDocument;
|
||||
|
||||
@@ -101,7 +101,7 @@ int main( int argc, char ** argv )
|
||||
std::string appName = App::Application::Config()["ExeName"];
|
||||
std::stringstream msg;
|
||||
msg << "While initializing " << appName << " the following exception occurred: '" << e.what() << "'\n\n";
|
||||
msg << "Python is searching for its runtime files in the following directories:\n" << Py_GetPath() << "\n\n";
|
||||
msg << "Python is searching for its runtime files in the following directories:\n" << Py_EncodeLocale(Py_GetPath(),nullptr) << "\n\n";
|
||||
msg << "Python version information:\n" << Py_GetVersion() << "\n";
|
||||
const char* pythonhome = getenv("PYTHONHOME");
|
||||
if ( pythonhome ) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -977,6 +977,8 @@ class _Wall(ArchComponent.Component):
|
||||
If "Length" has changed, record the old length so that .onChanged() can
|
||||
be sure that the base needs to be changed.
|
||||
|
||||
Also call ArchComponent.Component.onBeforeChange().
|
||||
|
||||
Parameters
|
||||
----------
|
||||
prop: string
|
||||
@@ -985,6 +987,7 @@ class _Wall(ArchComponent.Component):
|
||||
|
||||
if prop == "Length":
|
||||
self.oldLength = obj.Length.Value
|
||||
ArchComponent.Component.onBeforeChange(self,obj,prop)
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
"""Method called when the object has a property changed.
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -658,12 +658,12 @@ American Wide Flange,W27x178,H,357.886,706.12,18.415,30.226
|
||||
|
||||
# Category,Name,R,width,height
|
||||
|
||||
North America Lumber,1x2in,R,19,28
|
||||
North America Lumber,1x2in,R,19,38
|
||||
North America Lumber,1x3in,R,19,64
|
||||
North America Lumber,1x4in,R,19,89
|
||||
North America Lumber,1x6in,R,19,89
|
||||
North America Lumber,1x8in,R,19,140
|
||||
North America Lumber,1x10in,R,19,184
|
||||
North America Lumber,1x6in,R,19,140
|
||||
North America Lumber,1x8in,R,19,184
|
||||
North America Lumber,1x10in,R,19,235
|
||||
North America Lumber,1x12in,R,19,286
|
||||
North America Lumber,2x2in,R,38,38
|
||||
North America Lumber,2x3in,R,38,64
|
||||
@@ -679,7 +679,7 @@ North America Lumber,8x8in,R,184,184
|
||||
|
||||
# Eurocode timber
|
||||
|
||||
Eurocode timber,22x100 ,R,22,100
|
||||
Eurocode timber,22x100,R,22,100
|
||||
Eurocode timber,38x100,R,38,100
|
||||
Eurocode timber,38x150,R,38,150
|
||||
Eurocode timber,38x175,R,38,175
|
||||
|
||||
|
@@ -163,6 +163,9 @@ void DraftDxfRead::OnReadInsert(const double* point, const double* scale, const
|
||||
std::string prefix = "BLOCKS ";
|
||||
prefix += name;
|
||||
prefix += " ";
|
||||
auto checkScale = [=](double v) {
|
||||
return v != 0.0 ? v : 1.0;
|
||||
};
|
||||
for(std::map<std::string,std::vector<Part::TopoShape*> > ::const_iterator i = layers.begin(); i != layers.end(); ++i) {
|
||||
std::string k = i->first;
|
||||
if(k.substr(0, prefix.size()) == prefix) {
|
||||
@@ -178,7 +181,7 @@ void DraftDxfRead::OnReadInsert(const double* point, const double* scale, const
|
||||
if (!comp.IsNull()) {
|
||||
Part::TopoShape* pcomp = new Part::TopoShape(comp);
|
||||
Base::Matrix4D mat;
|
||||
mat.scale(scale[0],scale[1],scale[2]);
|
||||
mat.scale(checkScale(scale[0]),checkScale(scale[1]),checkScale(scale[2]));
|
||||
mat.rotZ(rotation);
|
||||
mat.move(point[0]*optionScaling,point[1]*optionScaling,point[2]*optionScaling);
|
||||
pcomp->transformShape(mat,true);
|
||||
|
||||
@@ -44,8 +44,8 @@ from draftmake.make_bspline import makeBSpline
|
||||
|
||||
def offset(obj, delta, copy=False, bind=False, sym=False, occ=False):
|
||||
"""offset(object,delta,[copymode],[bind])
|
||||
|
||||
Offset the given wire by applying the given delta Vector to its first
|
||||
|
||||
Offset the given wire by applying the given delta Vector to its first
|
||||
vertex.
|
||||
|
||||
Parameters
|
||||
@@ -63,7 +63,7 @@ def offset(obj, delta, copy=False, bind=False, sym=False, occ=False):
|
||||
copy : bool
|
||||
If bind is True, and provided the wire is open, the original
|
||||
and the offset wires will be bound by their endpoints, forming a face.
|
||||
|
||||
|
||||
sym : bool
|
||||
if sym is True, bind must be true too, and the offset is made on both
|
||||
sides, the total width being the given delta length.
|
||||
@@ -203,10 +203,10 @@ def offset(obj, delta, copy=False, bind=False, sym=False, occ=False):
|
||||
newobj.Closed = obj.Shape.isClosed()
|
||||
except Part.OCCError:
|
||||
pass
|
||||
if not(newobj) and newwire:
|
||||
if (not newobj) and newwire:
|
||||
newobj = App.ActiveDocument.addObject("Part::Feature","Offset")
|
||||
newobj.Shape = newwire
|
||||
else:
|
||||
if not newobj:
|
||||
print("Draft.offset: Unable to create an offset")
|
||||
if newobj:
|
||||
gui_utils.formatObject(newobj,obj)
|
||||
|
||||
@@ -212,6 +212,8 @@ def offsetWire(wire, dvec, bind=False, occ=False,
|
||||
# thus need to sort its edges same order
|
||||
edges = Part.__sortEdges__(wire.Edges)
|
||||
#edges = wire.Edges
|
||||
elif isinstance(wire, Part.Edge):
|
||||
edges = [wire]
|
||||
elif isinstance(wire, list):
|
||||
if isinstance(wire[0], Part.Edge):
|
||||
edges = wire.copy()
|
||||
|
||||
@@ -331,15 +331,13 @@ class Edit(gui_base_original.Modifier):
|
||||
# self.alignWorkingPlane()
|
||||
|
||||
|
||||
def numericInput(self, v, numy=None, numz=None):
|
||||
def numericInput(self, numx, numy, numz):
|
||||
"""Execute callback by the toolbar to activate the update function.
|
||||
|
||||
This function gets called by the toolbar
|
||||
or by the mouse click and activate the update function.
|
||||
"""
|
||||
if numy:
|
||||
v = App.Vector(v, numy, numz)
|
||||
self.endEditing(self.obj, self.editing, v)
|
||||
self.endEditing(self.obj, self.editing, App.Vector(numx, numy, numz))
|
||||
App.ActiveDocument.recompute()
|
||||
|
||||
|
||||
|
||||
@@ -197,6 +197,7 @@ class Move(gui_base_original.Modifier):
|
||||
|
||||
def move_subelements(self):
|
||||
"""Move the subelements."""
|
||||
Gui.addModule("Draft")
|
||||
try:
|
||||
if self.ui.isCopy.isChecked():
|
||||
self.commit(translate("draft", "Copy"),
|
||||
|
||||
@@ -272,6 +272,7 @@ class Rotate(gui_base_original.Modifier):
|
||||
|
||||
def rotate_subelements(self, is_copy):
|
||||
"""Rotate the subelements."""
|
||||
Gui.addModule("Draft")
|
||||
try:
|
||||
if is_copy:
|
||||
self.commit(translate("draft", "Copy"),
|
||||
|
||||
@@ -193,6 +193,7 @@ class Scale(gui_base_original.Modifier):
|
||||
the selected object is not a rectangle or another object
|
||||
that can't be used with `scaleVertex` and `scaleEdge`.
|
||||
"""
|
||||
Gui.addModule("Draft")
|
||||
try:
|
||||
if self.task.isCopy.isChecked():
|
||||
self.commit(translate("draft", "Copy"),
|
||||
|
||||
@@ -119,6 +119,7 @@ class PointArray(DraftLink):
|
||||
"""Run when the object is created or recomputed."""
|
||||
|
||||
pt_list, count = get_point_list(obj.PointObject)
|
||||
obj.Count = count
|
||||
pls = build_placements(obj.Base, pt_list, obj.ExtraPlacement)
|
||||
|
||||
return super(PointArray, self).buildShape(obj, obj.Placement, pls)
|
||||
|
||||
@@ -227,12 +227,14 @@ class Wire(DraftObject):
|
||||
obj.Points = pts
|
||||
|
||||
elif prop == "Length":
|
||||
if obj.Shape and not obj.Shape.isNull():
|
||||
if obj.Length.Value != obj.Shape.Length:
|
||||
if len(obj.Points) == 2:
|
||||
v = obj.Points[-1].sub(obj.Points[0])
|
||||
v = DraftVecUtils.scaleTo(v,obj.Length.Value)
|
||||
obj.Points = [obj.Points[0],obj.Points[0].add(v)]
|
||||
if (len(obj.Points) == 2
|
||||
and obj.Length.Value > 1e-7
|
||||
and obj.Shape
|
||||
and (not obj.Shape.isNull())
|
||||
and obj.Length.Value != obj.Shape.Length):
|
||||
v = obj.Points[-1].sub(obj.Points[0])
|
||||
v = DraftVecUtils.scaleTo(v, obj.Length.Value)
|
||||
obj.Points = [obj.Points[0], obj.Points[0].add(v)]
|
||||
|
||||
elif prop == "Placement":
|
||||
pl = App.Placement(obj.Placement)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
\brief Airfoil (.dat) file importer
|
||||
|
||||
This module provides support for importing airfoil .dat files.
|
||||
Note (2019): this module has been unmaintained for a long time.
|
||||
'''
|
||||
# Check code with
|
||||
# flake8 --ignore=E226,E266,E401,W503
|
||||
@@ -103,8 +102,9 @@ def open(filename):
|
||||
"""
|
||||
docname = os.path.splitext(os.path.basename(filename))[0]
|
||||
doc = FreeCAD.newDocument(docname)
|
||||
doc.Label = decodeName(docname[:-4])
|
||||
process(doc, filename)
|
||||
doc.Label = decodeName(docname)
|
||||
process(filename)
|
||||
doc.recompute()
|
||||
|
||||
|
||||
def insert(filename, docname):
|
||||
@@ -131,13 +131,16 @@ def insert(filename, docname):
|
||||
doc = FreeCAD.getDocument(docname)
|
||||
except NameError:
|
||||
doc = FreeCAD.newDocument(docname)
|
||||
importgroup = doc.addObject("App::DocumentObjectGroup", groupname)
|
||||
importgroup.Label = decodeName(groupname)
|
||||
process(doc, filename)
|
||||
obj = process(filename)
|
||||
if obj is not None:
|
||||
importgroup = doc.addObject("App::DocumentObjectGroup", groupname)
|
||||
importgroup.Label = decodeName(groupname)
|
||||
importgroup.Group = [obj]
|
||||
doc.recompute()
|
||||
|
||||
|
||||
def process(doc, filename):
|
||||
"""Process the filename and provide the document with the information.
|
||||
def process(filename):
|
||||
"""Process the filename and create a Draft Wire from the data.
|
||||
|
||||
The common airfoil dat format has many flavors.
|
||||
This code should work with almost every dialect.
|
||||
@@ -146,18 +149,15 @@ def process(doc, filename):
|
||||
----------
|
||||
filename : str
|
||||
The path to the filename to be opened.
|
||||
docname : str
|
||||
The name of the active App::Document if one exists, or
|
||||
of the new one created.
|
||||
|
||||
Returns
|
||||
-------
|
||||
App::Document
|
||||
The active FreeCAD document, or the document created if none exists,
|
||||
with the parsed information.
|
||||
Part::Part2DObject or None.
|
||||
The created Draft Wire object or None if the file contains less
|
||||
than 3 points.
|
||||
"""
|
||||
# Regex to identify data rows and throw away unused metadata
|
||||
xval = r'(?P<xval>(\-|\d*)\.*\d*([Ee]\-?\d+)?)'
|
||||
xval = r'(?P<xval>\-?\s*\d*\.*\d*([Ee]\-?\d+)?)'
|
||||
yval = r'(?P<yval>\-?\s*\d*\.*\d*([Ee]\-?\d+)?)'
|
||||
_regex = r'^\s*' + xval + r'\,?\s*' + yval + r'\s*$'
|
||||
|
||||
@@ -170,21 +170,28 @@ def process(doc, filename):
|
||||
# upside = True
|
||||
# last_x = None
|
||||
|
||||
# Collect the data for the upper and the lower side separately if possible
|
||||
# Collect the data
|
||||
for lin in afile:
|
||||
curdat = regex.match(lin)
|
||||
if curdat is not None:
|
||||
if (curdat is not None
|
||||
and curdat.group("xval")
|
||||
and curdat.group("yval")):
|
||||
x = float(curdat.group("xval"))
|
||||
y = float(curdat.group("yval"))
|
||||
|
||||
# the normal processing
|
||||
coords.append(Vector(x, y, 0))
|
||||
# Some files specify the number of upper and lower points on the 2nd line:
|
||||
# " 67. 72."
|
||||
# See: http://airfoiltools.com/airfoil
|
||||
# This line must be skipped:
|
||||
if x < 2 and y < 2:
|
||||
# the normal processing
|
||||
coords.append(Vector(x, y, 0))
|
||||
|
||||
afile.close()
|
||||
|
||||
if len(coords) < 3:
|
||||
print('Did not find enough coordinates\n')
|
||||
return
|
||||
return None
|
||||
|
||||
# sometimes coords are divided in upper an lower side
|
||||
# so that x-coordinate begin new from leading or trailing edge
|
||||
@@ -227,4 +234,4 @@ def process(doc, filename):
|
||||
obj = FreeCAD.ActiveDocument.addObject('Part::Feature', airfoilname)
|
||||
obj.Shape = face
|
||||
|
||||
doc.recompute()
|
||||
return obj
|
||||
|
||||
@@ -44,8 +44,6 @@ https://knowledge.autodesk.com/support/autocad/downloads/
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
# TODO: use subprocess.popen() instead of subprocess.call()
|
||||
|
||||
import six
|
||||
import FreeCAD
|
||||
from FreeCAD import Console as FCC
|
||||
@@ -217,10 +215,10 @@ def convertToDxf(dwgfilename):
|
||||
indir = os.path.dirname(dwgfilename)
|
||||
outdir = tempfile.mkdtemp()
|
||||
basename = os.path.basename(dwgfilename)
|
||||
cmdline = ('"%s" "%s" "%s" "ACAD2000" "DXF" "0" "1" "%s"'
|
||||
% (teigha, indir, outdir, basename))
|
||||
FCC.PrintMessage(translate("ImportDWG", "Converting: ")
|
||||
+ cmdline + "\n")
|
||||
cmdline = [teigha, indir, outdir, "ACAD2000", "DXF", "0", "1", basename]
|
||||
FCC.PrintMessage(translate("draft", "Converting:") + " " + str(cmdline) + "\n")
|
||||
proc = subprocess.Popen(cmdline)
|
||||
proc.communicate()
|
||||
if six.PY2:
|
||||
if isinstance(cmdline, six.text_type):
|
||||
encoding = sys.getfilesystemencoding()
|
||||
@@ -270,10 +268,9 @@ def convertToDwg(dxffilename, dwgfilename):
|
||||
indir = os.path.dirname(dxffilename)
|
||||
outdir = os.path.dirname(dwgfilename)
|
||||
basename = os.path.basename(dxffilename)
|
||||
cmdline = ('"%s" "%s" "%s" "ACAD2000" "DWG" "0" "1" "%s"'
|
||||
% (teigha, indir, outdir, basename))
|
||||
FCC.PrintMessage(translate("ImportDWG", "Converting: ")
|
||||
+ cmdline + "\n")
|
||||
subprocess.call(cmdline, shell=True) # os.system(cmdline)
|
||||
cmdline = [teigha, indir, outdir, "ACAD2000", "DWG", "0", "1", basename]
|
||||
FCC.PrintMessage(translate("draft", "Converting:") + " " + str(cmdline) + "\n")
|
||||
proc = subprocess.Popen(cmdline)
|
||||
proc.communicate()
|
||||
return dwgfilename
|
||||
return None
|
||||
|
||||
@@ -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
|
||||
@@ -3660,6 +3662,10 @@ def export(objectslist, filename, nospline=False, lwPoly=False):
|
||||
else:
|
||||
# other cases, treat objects one by one
|
||||
dxf = dxfLibrary.Drawing()
|
||||
# add global variables
|
||||
if hasattr(dxf,"header"):
|
||||
dxf.header.append(" 9\n$DIMTXT\n 40\n"+str(Draft.getParam("textheight", 20))+"\n")
|
||||
dxf.header.append(" 9\n$INSUNITS\n 70\n4\n")
|
||||
|
||||
for ob in exportLayers:
|
||||
if ob.Label != "0": # dxflibrary already creates it
|
||||
|
||||
@@ -1044,19 +1044,12 @@ class svgHandler(xml.sax.ContentHandler):
|
||||
# angle1 - 0 * swapaxis * d90,
|
||||
# angle1 + angledelta
|
||||
# - 0 * swapaxis * d90)
|
||||
_precision = 10**(-1*Draft.precision())
|
||||
if swapaxis or xrotation > _precision:
|
||||
m3 = FreeCAD.Matrix()
|
||||
m3.move(vcenter)
|
||||
# 90
|
||||
rot90 = FreeCAD.Matrix(0, -1, 0, 0, 1, 0)
|
||||
# swapaxism = FreeCAD.Matrix(0, 1, 0, 0, 1, 0)
|
||||
if swapaxis:
|
||||
m3 = m3.multiply(rot90)
|
||||
m3.rotateZ(math.radians(-xrotation))
|
||||
m3.move(vcenter.multiply(-1))
|
||||
e1a.transform(m3)
|
||||
seg = e1a.toShape()
|
||||
if swapaxis:
|
||||
seg.rotate(vcenter, Vector(0, 0, 1), 90)
|
||||
_precision = 10**(-1*Draft.precision())
|
||||
if abs(xrotation) > _precision:
|
||||
seg.rotate(vcenter, Vector(0, 0, 1), -xrotation)
|
||||
if sweepflag:
|
||||
seg.reverse()
|
||||
# DEBUG
|
||||
@@ -1380,14 +1373,7 @@ class svgHandler(xml.sax.ContentHandler):
|
||||
sh = Part.Ellipse(c, rx, ry).toShape()
|
||||
else:
|
||||
sh = Part.Ellipse(c, ry, rx).toShape()
|
||||
m3 = FreeCAD.Matrix()
|
||||
m3.move(c)
|
||||
# 90
|
||||
rot90 = FreeCAD.Matrix(0, -1, 0, 0, 1, 0)
|
||||
m3 = m3.multiply(rot90)
|
||||
m3.move(c.multiply(-1))
|
||||
sh.transformShape(m3)
|
||||
# sh = sh.transformGeometry(m3)
|
||||
sh.rotate(c, Vector(0, 0, 1), 90)
|
||||
if self.fill:
|
||||
sh = Part.Wire([sh])
|
||||
sh = Part.Face(sh)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,6 +313,9 @@ void ImpExpDxfRead::OnReadInsert(const double* point, const double* scale, const
|
||||
std::string prefix = "BLOCKS ";
|
||||
prefix += name;
|
||||
prefix += " ";
|
||||
auto checkScale = [=](double v) {
|
||||
return v != 0.0 ? v : 1.0;
|
||||
};
|
||||
for(std::map<std::string,std::vector<Part::TopoShape*> > ::const_iterator i = layers.begin(); i != layers.end(); ++i) {
|
||||
std::string k = i->first;
|
||||
if(k.substr(0, prefix.size()) == prefix) {
|
||||
@@ -328,7 +331,7 @@ void ImpExpDxfRead::OnReadInsert(const double* point, const double* scale, const
|
||||
if (!comp.IsNull()) {
|
||||
Part::TopoShape* pcomp = new Part::TopoShape(comp);
|
||||
Base::Matrix4D mat;
|
||||
mat.scale(scale[0],scale[1],scale[2]);
|
||||
mat.scale(checkScale(scale[0]),checkScale(scale[1]),checkScale(scale[2]));
|
||||
mat.rotZ(rotation);
|
||||
mat.move(point[0]*optionScaling,point[1]*optionScaling,point[2]*optionScaling);
|
||||
pcomp->transformShape(mat,true);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1770,7 +1770,13 @@ CDxfRead::~CDxfRead()
|
||||
|
||||
double CDxfRead::mm( double value ) const
|
||||
{
|
||||
if(m_measurement_inch)
|
||||
//re #6461
|
||||
//this if handles situation of malformed DXF file where
|
||||
//MEASUREMENT specifies English units, but
|
||||
//INSUNITS specifies millimeters or is not specified
|
||||
//(millimeters is our default)
|
||||
if(m_measurement_inch &&
|
||||
(m_eUnits == eMillimeters))
|
||||
{
|
||||
value *= 25.4;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -88,11 +88,11 @@ std::unique_ptr<Part::GeometryExtension> GeometryDefaultExtension<T>::copy(void)
|
||||
// That would work perfectly with GCC 7.3.0. However, GCC 4.8.4 misserably fails:
|
||||
//
|
||||
// /home/travis/build/FreeCAD/FreeCAD/src/Mod/Part/App/GeometryDefaultExtension.cpp: In instantiation of
|
||||
// ‘std::unique_ptr<Part::GeometryExtension> Part::GeometryDefaultExtension<T>::copy() const [with T = long int]’:
|
||||
// 'std::unique_ptr<Part::GeometryExtension> Part::GeometryDefaultExtension<T>::copy() const [with T = long int]':
|
||||
// /home/travis/build/FreeCAD/FreeCAD/src/Mod/Part/App/GeometryDefaultExtension.cpp:164:16: required from here
|
||||
// /home/travis/build/FreeCAD/FreeCAD/src/Mod/Part/App/GeometryDefaultExtension.cpp:84:12: error: cannot bind //
|
||||
// ‘std::unique_ptr<Part::GeometryDefaultExtension<long int>, std::default_delete<Part::GeometryDefaultExtension<long int> > >’ lvalue
|
||||
// to ‘std::unique_ptr<Part::GeometryDefaultExtension<long int>, std::default_delete<Part::GeometryDefaultExtension<long int> > >&&’
|
||||
// 'std::unique_ptr<Part::GeometryDefaultExtension<long int>, std::default_delete<Part::GeometryDefaultExtension<long int> > >' lvalue
|
||||
// to 'std::unique_ptr<Part::GeometryDefaultExtension<long int>, std::default_delete<Part::GeometryDefaultExtension<long int> > >&&'
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1715,6 +1715,7 @@ bool TopoShape::analyze(bool runBopCheck, std::ostream& str) const
|
||||
#endif
|
||||
#if OCC_VERSION_HEX >= 0x060900
|
||||
BOPCheck.SetParallelMode(true); //this doesn't help for speed right now(occt 6.9.1).
|
||||
BOPCheck.SetRunParallel(true); //performance boost, use all available cores
|
||||
BOPCheck.TangentMode() = true; //these 4 new tests add about 5% processing time.
|
||||
BOPCheck.MergeVertexMode() = true;
|
||||
BOPCheck.CurveOnSurfaceMode() = true;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ public:
|
||||
std::string subName(sSubName);
|
||||
if (subName.empty()) return false;
|
||||
|
||||
auto subShape = aPart->Shape.getShape().getSubShape(sSubName);
|
||||
auto subShape = aPart->Shape.getShape().getSubShape(sSubName, true);
|
||||
if (subShape.IsNull()) return false;
|
||||
auto type = subShape.ShapeType();
|
||||
if (type != TopAbs_FACE) return false;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -70,17 +70,6 @@ void ViewProviderPrimitive::setupContextMenu(QMenu* menu, QObject* receiver, con
|
||||
ViewProviderPart::setupContextMenu(menu, receiver, member);
|
||||
}
|
||||
|
||||
void ViewProviderPrimitive::startDefaultEditMode()
|
||||
{
|
||||
QString text = QObject::tr("Edit %1").arg(QString::fromUtf8(getObject()->Label.getValue()));
|
||||
Gui::Command::openCommand(text.toUtf8());
|
||||
|
||||
Gui::Document* document = this->getDocument();
|
||||
if (document) {
|
||||
document->setEdit(this, ViewProvider::Default);
|
||||
}
|
||||
}
|
||||
|
||||
bool ViewProviderPrimitive::setEdit(int ModNum)
|
||||
{
|
||||
if (ModNum == ViewProvider::Default) {
|
||||
|
||||
@@ -46,9 +46,6 @@ protected:
|
||||
bool setEdit(int ModNum);
|
||||
void unsetEdit(int ModNum);
|
||||
|
||||
private:
|
||||
void startDefaultEditMode();
|
||||
|
||||
private:
|
||||
ViewProviderAttachExtension extension;
|
||||
};
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -791,9 +791,9 @@ void Hole::updateHoleCutParams()
|
||||
}
|
||||
}
|
||||
|
||||
// handle legacy types but don’t change user settings for
|
||||
// handle legacy types but don't change user settings for
|
||||
// user defined None, Counterbore and Countersink
|
||||
// handle legacy types but don’t change user settings for
|
||||
// handle legacy types but don't change user settings for
|
||||
// user defined None, Counterbore and Countersink
|
||||
else if (holeCutTypeStr == "Cheesehead (deprecated)") {
|
||||
HoleCutDiameter.setValue(diameterVal * 1.6);
|
||||
@@ -1886,7 +1886,7 @@ void from_json(const nlohmann::json &j, Hole::CutDimensionSet &t)
|
||||
else if (thread_type_string == "metricfine")
|
||||
t.thread_type = Hole::CutDimensionSet::MetricFine;
|
||||
else
|
||||
throw Base::IndexError(std::string("Thread type ‘") + thread_type_string + "’ unsupported");
|
||||
throw Base::IndexError(std::string("Thread type '") + thread_type_string + "' unsupported");
|
||||
|
||||
std::string cut_type_string = j["cut_type"].get<std::string>();
|
||||
if (cut_type_string == "counterbore") {
|
||||
@@ -1899,7 +1899,7 @@ void from_json(const nlohmann::json &j, Hole::CutDimensionSet &t)
|
||||
t.angle = j["angle"].get<double>();
|
||||
}
|
||||
else
|
||||
throw Base::IndexError(std::string("Cut type ‘") + cut_type_string + "’ unsupported");
|
||||
throw Base::IndexError(std::string("Cut type '") + cut_type_string + "' unsupported");
|
||||
|
||||
t.name = j["name"].get<std::string>();
|
||||
}
|
||||
@@ -1928,7 +1928,7 @@ void Hole::readCutDefinitions()
|
||||
addCutType(screwtype);
|
||||
}
|
||||
catch(std::exception &e) {
|
||||
std::cerr << "Failed reading ‘" << f.filePath() << "’ with: "<< e.what() << "\n";
|
||||
std::cerr << "Failed reading '" << f.filePath() << "' with: "<< e.what() << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -588,8 +588,10 @@ void ProfileBased::generatePrism(TopoDS_Shape& prism,
|
||||
// midplane makes no sense here
|
||||
Loffset = -L2;
|
||||
Ltotal += L2;
|
||||
} else if (midplane)
|
||||
Loffset = -Ltotal/2;
|
||||
}
|
||||
else if (midplane) {
|
||||
Loffset = -Ltotal / 2;
|
||||
}
|
||||
|
||||
TopoDS_Shape from = sketchshape;
|
||||
if (method == "TwoLengths" || midplane) {
|
||||
@@ -597,8 +599,17 @@ void ProfileBased::generatePrism(TopoDS_Shape& prism,
|
||||
mov.SetTranslation(Loffset * gp_Vec(dir));
|
||||
TopLoc_Location loc(mov);
|
||||
from = sketchshape.Moved(loc);
|
||||
} else if (reversed)
|
||||
}
|
||||
else if (reversed) {
|
||||
Ltotal *= -1.0;
|
||||
}
|
||||
|
||||
if (fabs(Ltotal) < Precision::Confusion()) {
|
||||
if (addSubType == Type::Additive)
|
||||
throw Base::ValueError("Cannot create a pad with a height of zero.");
|
||||
else
|
||||
throw Base::ValueError("Cannot create a pocket with a depth of zero.");
|
||||
}
|
||||
|
||||
// Its better not to use BRepFeat_MakePrism here even if we have a support because the
|
||||
// resulting shape creates problems with Pocket
|
||||
|
||||
@@ -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();
|
||||
@@ -273,6 +275,7 @@ void TaskMultiTransformParameters::onTransformEdit()
|
||||
else
|
||||
return; // TODO: Show an error?
|
||||
|
||||
subTask->setEnabledTransaction(isEnabledTransaction());
|
||||
connect(ui->checkBoxUpdateView, SIGNAL(toggled(bool)),
|
||||
subTask, SLOT(onUpdateView(bool)));
|
||||
}
|
||||
@@ -288,17 +291,25 @@ 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<<"')");
|
||||
if (isEnabledTransaction())
|
||||
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Mirrored"));
|
||||
|
||||
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 +319,37 @@ 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<<"')");
|
||||
if (isEnabledTransaction())
|
||||
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Make LinearPattern"));
|
||||
|
||||
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 +357,27 @@ 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<<"')");
|
||||
if (isEnabledTransaction())
|
||||
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "PolarPattern"));
|
||||
|
||||
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 +385,24 @@ 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<<"')");
|
||||
if (isEnabledTransaction())
|
||||
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Scaled"));
|
||||
|
||||
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)
|
||||
@@ -468,7 +503,6 @@ void TaskMultiTransformParameters::onUpdateView(bool on)
|
||||
{
|
||||
blockUpdate = !on;
|
||||
if (on) {
|
||||
setupTransaction();
|
||||
recomputeFeature();
|
||||
}
|
||||
}
|
||||
@@ -513,6 +547,7 @@ TaskDlgMultiTransformParameters::TaskDlgMultiTransformParameters(ViewProviderMul
|
||||
: TaskDlgTransformedParameters(MultiTransformView)
|
||||
{
|
||||
parameter = new TaskMultiTransformParameters(MultiTransformView);
|
||||
parameter->setEnabledTransaction(false);
|
||||
|
||||
Content.push_back(parameter);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -170,6 +170,9 @@ bool TaskTransformedParameters::originalSelected(const Gui::SelectionChanges& ms
|
||||
|
||||
void TaskTransformedParameters::setupTransaction()
|
||||
{
|
||||
if (!isEnabledTransaction())
|
||||
return;
|
||||
|
||||
auto obj = getObject();
|
||||
if (!obj)
|
||||
return;
|
||||
@@ -185,6 +188,16 @@ void TaskTransformedParameters::setupTransaction()
|
||||
transactionID = App::GetApplication().setActiveTransaction(n.c_str());
|
||||
}
|
||||
|
||||
void TaskTransformedParameters::setEnabledTransaction(bool on)
|
||||
{
|
||||
enableTransaction = on;
|
||||
}
|
||||
|
||||
bool TaskTransformedParameters::isEnabledTransaction() const
|
||||
{
|
||||
return enableTransaction;
|
||||
}
|
||||
|
||||
void TaskTransformedParameters::onButtonAddFeature(bool checked)
|
||||
{
|
||||
if (checked) {
|
||||
@@ -322,13 +335,15 @@ PartDesignGui::ViewProviderTransformed *TaskTransformedParameters::getTopTransfo
|
||||
} else {
|
||||
rv = TransformedView;
|
||||
}
|
||||
assert (rv);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
PartDesign::Transformed *TaskTransformedParameters::getTopTransformedObject() const {
|
||||
App::DocumentObject *transform = getTopTransformedView()->getObject();
|
||||
ViewProviderTransformed* vp = getTopTransformedView();
|
||||
if (!vp)
|
||||
return nullptr;
|
||||
|
||||
App::DocumentObject *transform = vp->getObject();
|
||||
assert (transform->isDerivedFrom(PartDesign::Transformed::getClassTypeId()));
|
||||
return static_cast<PartDesign::Transformed*>(transform);
|
||||
}
|
||||
@@ -344,6 +359,9 @@ PartDesign::Transformed *TaskTransformedParameters::getObject() const {
|
||||
|
||||
App::DocumentObject *TaskTransformedParameters::getBaseObject() const {
|
||||
PartDesign::Feature* feature = getTopTransformedObject ();
|
||||
if (!feature)
|
||||
return nullptr;
|
||||
|
||||
// NOTE: getBaseObject() throws if there is no base; shouldn't happen here.
|
||||
App::DocumentObject *base = feature->getBaseObject(true);
|
||||
if(!base) {
|
||||
@@ -355,7 +373,8 @@ App::DocumentObject *TaskTransformedParameters::getBaseObject() const {
|
||||
}
|
||||
|
||||
App::DocumentObject* TaskTransformedParameters::getSketchObject() const {
|
||||
return getTopTransformedObject()->getSketchObject();
|
||||
PartDesign::Transformed* feature = getTopTransformedObject();
|
||||
return feature ? feature->getSketchObject() : nullptr;
|
||||
}
|
||||
|
||||
void TaskTransformedParameters::hideObject()
|
||||
|
||||
@@ -142,6 +142,14 @@ public:
|
||||
|
||||
virtual void apply() = 0;
|
||||
|
||||
/*!
|
||||
* \brief setEnabledTransaction
|
||||
* The transaction handling of this panel can be disabled if there is another
|
||||
* instance that does it already, e.g. TaskDlgMultiTransformParameters.
|
||||
* By default, transactions are enabled.
|
||||
*/
|
||||
void setEnabledTransaction(bool);
|
||||
bool isEnabledTransaction() const;
|
||||
void setupTransaction();
|
||||
|
||||
int getTransactionID() const {
|
||||
@@ -212,6 +220,7 @@ protected:
|
||||
QWidget* proxy;
|
||||
ViewProviderTransformed *TransformedView;
|
||||
int transactionID = 0;
|
||||
bool enableTransaction = true;
|
||||
|
||||
enum selectionModes { none, addFeature, removeFeature, reference };
|
||||
selectionModes selectionMode;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -39,6 +39,12 @@ TaskDlgFeatureParameters *ViewProviderMultiTransform::getEditDialog() {
|
||||
return new TaskDlgMultiTransformParameters (this);
|
||||
}
|
||||
|
||||
void ViewProviderMultiTransform::setupContextMenu(QMenu* menu, QObject* receiver, const char* member)
|
||||
{
|
||||
this->addDefaultAction(menu, QObject::tr("Edit %1").arg(QString::fromStdString(featureName)));
|
||||
PartDesignGui::ViewProvider::setupContextMenu(menu, receiver, member);
|
||||
}
|
||||
|
||||
std::vector<App::DocumentObject*> ViewProviderMultiTransform::claimChildren(void) const
|
||||
{
|
||||
PartDesign::MultiTransform* pcMultiTransform = static_cast<PartDesign::MultiTransform*>(getObject());
|
||||
|
||||
@@ -37,14 +37,13 @@ public:
|
||||
sPixmap = "PartDesign_MultiTransform.svg"; }
|
||||
|
||||
std::vector<App::DocumentObject*> claimChildren(void) const;
|
||||
void setupContextMenu(QMenu*, QObject*, const char*);
|
||||
|
||||
virtual bool onDelete(const std::vector<std::string> &);
|
||||
|
||||
protected:
|
||||
/// Returns a newly create dialog for the part to be placed in the task view
|
||||
virtual TaskDlgFeatureParameters *getEditDialog();
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1230,7 +1230,7 @@ int Area::project(TopoDS_Shape &shape_out,
|
||||
const TopoDS_Shape *work_plane)
|
||||
{
|
||||
FC_TIME_INIT2(t,t1);
|
||||
Handle_HLRBRep_Algo brep_hlr = NULL;
|
||||
Handle_HLRBRep_Algo brep_hlr;
|
||||
gp_Dir dir(0,0,1);
|
||||
try {
|
||||
brep_hlr = new HLRBRep_Algo();
|
||||
|
||||
@@ -36,6 +36,7 @@ Part = LazyLoader('Part', globals(), 'Part')
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
PathGeom = LazyLoader("PathScripts.PathGeom", globals(), "PathScripts.PathGeom")
|
||||
|
||||
__title__ = "Base class for PathArea based operations."
|
||||
__author__ = "sliptonic (Brad Collette)"
|
||||
@@ -305,11 +306,18 @@ class ObjectOp(PathOp.ObjectOp):
|
||||
pathParams['preamble'] = False
|
||||
|
||||
if self.endVector is None:
|
||||
V = hWire.Wires[0].Vertexes
|
||||
lv = len(V) - 1
|
||||
pathParams['start'] = FreeCAD.Vector(V[0].X, V[0].Y, V[0].Z)
|
||||
if obj.Direction == 'CCW':
|
||||
pathParams['start'] = FreeCAD.Vector(V[lv].X, V[lv].Y, V[lv].Z)
|
||||
verts = hWire.Wires[0].Vertexes
|
||||
idx = 0
|
||||
if obj.Direction == "CCW":
|
||||
idx = len(verts) - 1
|
||||
x = verts[idx].X
|
||||
y = verts[idx].Y
|
||||
# Zero start value adjustments for Path.fromShapes() bug
|
||||
if PathGeom.isRoughly(x, 0.0):
|
||||
x = 0.00001
|
||||
if PathGeom.isRoughly(y, 0.0):
|
||||
y = 0.00001
|
||||
pathParams["start"] = FreeCAD.Vector(x, y, verts[0].Z)
|
||||
else:
|
||||
pathParams['start'] = self.endVector
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user