diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fdc40a316b..8568d5c631 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,6 +16,7 @@ files: | src/Mod/Surface| src/Mod/Start| src/Mod/Test| + src/Mod/Tux| src/Mod/Web ) exclude: | diff --git a/src/FCConfig.h b/src/FCConfig.h index 9ddce84b52..a075b010ea 100644 --- a/src/FCConfig.h +++ b/src/FCConfig.h @@ -51,16 +51,7 @@ # if HAVE_CONFIG_H # include # endif // HAVE_CONFIG_H -//# define HAVE_INT8_T -//# define HAVE_UINT8_T -//# define HAVE_INT16_T -//# define HAVE_UINT16_T -//# define HAVE_INT32_T -//# define HAVE_UINT32_T -//# define HAVE_INT64_T -//# define HAVE_UINT64_T -//# define HAVE_INTPTR_T -//# define HAVE_UINTPTR_T + # endif #elif defined(__MWERKS__) && defined(__INTEL__) # ifndef FC_OS_WIN32 @@ -93,26 +84,7 @@ # define HAVE_INTPTR_T # define HAVE_UINTPTR_T #endif -//#elif defined(sun) || defined(__sun) || defined(__sun__) -//# if defined(__SVR4) -//# define _FC_OS_SOLARIS -//# else -//# define _FC_OS_SUN_ -//# endif -//#elif defined(hpux) || defined(__hpux) || defined(__hpux__) -//# define FC_OS_HPUX_ -//#elif defined(__FreeBSD__) -//# define FC_OS_FREEBSD -//#elif defined(__NetBSD__) -//# define FC_OS_NETBSD -//#elif defined(__OpenBSD__) -//# define FC_OS_OPENBSD -//#elif defined(sgi) || defined(__sgi) -//# define FC_OS_IRIX -//#elif defined(_AIX) -//# define FC_OS_AIX -//#elif defined(__GNU__) -//# define FC_OS_GNU + #else # error "FreeCAD is not ported to this OS yet. For help see www.freecad.org" #endif @@ -203,7 +175,6 @@ typedef unsigned __int64 uint64_t; #ifdef FC_OS_LINUX # define LIN # define LININTEL -//# define NO_CXX_EXCEPTION #endif #define CSFDB @@ -263,14 +234,6 @@ typedef unsigned __int64 uint64_t; # endif #endif -//************************************************************************** -// SoQt -#if defined (FC_OS_WIN32) || defined(FC_OS_CYGWIN) -# ifndef SOQT_DLL -# define SOQT_DLL -# endif -#endif - //************************************************************************** // Quarter #if defined (FC_OS_WIN32) || defined(FC_OS_CYGWIN) @@ -281,15 +244,13 @@ typedef unsigned __int64 uint64_t; # endif #endif -// stops inclusion of the QT 3 header through the SoQT header... -//#define __Qt3All__ - //************************************************************************** // Boost #ifndef BOOST_SIGNALS_NO_DEPRECATION_WARNING #define BOOST_SIGNALS_NO_DEPRECATION_WARNING #endif + //************************************************************************** // Exception handling @@ -314,15 +275,12 @@ typedef unsigned __int64 uint64_t; // point at which warnings of overly long specifiers disabled (needed for VC6) #ifdef _MSC_VER # pragma warning( disable : 4251 ) -//# pragma warning( disable : 4503 ) -//# pragma warning( disable : 4786 ) // specifier longer then 255 chars -//# pragma warning( disable : 4290 ) // not implemented throw specification # pragma warning( disable : 4996 ) // suppress deprecated warning for e.g. open() #if defined(WIN64) || defined(_WIN64) || defined(__WIN64__) # pragma warning( disable : 4244 ) # pragma warning( disable : 4267 ) #endif -//# define _PreComp_ // use precompiled header + #endif #endif //FC_CONFIG_H diff --git a/src/Gui/3Dconnexion/GuiNativeEventLinuxX11.cpp b/src/Gui/3Dconnexion/GuiNativeEventLinuxX11.cpp index 2ef1c983ff..f6bd8a955f 100644 --- a/src/Gui/3Dconnexion/GuiNativeEventLinuxX11.cpp +++ b/src/Gui/3Dconnexion/GuiNativeEventLinuxX11.cpp @@ -33,23 +33,22 @@ #include #include -#if QT_VERSION >= 0x050000 - #include "GuiRawInputEventFilter.h" - #undef Bool - #undef CursorShape - #undef Expose - #undef KeyPress - #undef KeyRelease - #undef FocusIn - #undef FocusOut - #undef FontChange - #undef None - #undef Status - #undef Unsorted - #undef False - #undef True - #undef Complex -#endif // #if QT_VERSION >= 0x050000 +#include "GuiRawInputEventFilter.h" +#undef Bool +#undef CursorShape +#undef Expose +#undef KeyPress +#undef KeyRelease +#undef FocusIn +#undef FocusOut +#undef FontChange +#undef None +#undef Status +#undef Unsorted +#undef False +#undef True +#undef Complex + Gui::GuiNativeEvent::GuiNativeEvent(Gui::GUIApplicationNativeEventAware *app) : GuiAbstractNativeEvent(app) @@ -66,26 +65,19 @@ Gui::GuiNativeEvent::~GuiNativeEvent() void Gui::GuiNativeEvent::initSpaceball(QMainWindow *window) { -#if QT_VERSION >= 0x050200 if (!QX11Info::isPlatformX11()) { Base::Console().Log("Application is not running on X11\n"); return; } -#endif if (spnav_x11_open(QX11Info::display(), window->winId()) == -1) { Base::Console().Log("Couldn't connect to spacenav daemon on X11. Please ignore if you don't have a spacemouse.\n"); } else { Base::Console().Log("Connected to spacenav daemon on X11\n"); mainApp->setSpaceballPresent(true); - -#if QT_VERSION >= 0x050000 mainApp->installNativeEventFilter(new Gui::RawInputEventFilter(&xcbEventFilter)); -#endif // #if QT_VERSION >= 0x050000 } } -#if QT_VERSION >= 0x050000 - bool Gui::GuiNativeEvent::xcbEventFilter(void *xcb_void, long* result) { Q_UNUSED(result); @@ -151,117 +143,4 @@ bool Gui::GuiNativeEvent::xcbEventFilter(void *xcb_void, long* result) } // end switch (navEvent.type) { } -#else // if QT_VERSION >= 0x050000 - -bool Gui::GuiNativeEvent::x11EventFilter(XEvent *event) -{ - /* - First we check if we have a motion flush event: - - If there are unprocessed motion events we are in a flooding situation. - In that case we wait with generating a Spaceball event. - - A motion event counter of 0 indicates that FreeCAD is ready to process - the event. A Spaceball event, using the saved motion data, is posted. - */ - static Display* display = QX11Info::display(); - static Atom motion_flush_event = XInternAtom(display, "FCMotionFlushEvent", false); - static int nMotionEvents = 0; - - if (event->type == ClientMessage) - { - Atom message_type = event->xclient.message_type; - - if (message_type == motion_flush_event) - { - nMotionEvents--; - if (nMotionEvents == 0) - { - mainApp->postMotionEvent(motionDataArray); - } - - return true; - } // XEvent: motion_flush_event - } // XEvent: ClientMessage - - /* - From here on we deal with spacenav events only: - - motion: The event data is saved and a self addressed flush event - is sent through the window system (XEvent). - In the case of an event flooding, the motion data is added up. - - button: A Spaceball event is posted (QInputEvent). - */ - spnav_event navEvent; - if (!spnav_x11_event(event, &navEvent)) - return false; - - if (navEvent.type == SPNAV_EVENT_MOTION) - { - /* - If the motion data of the preceding event has not been processed - through posting an Spaceball event (flooding situation), - the motion data provided by the incoming event is added to the saved data. - */ - int dx, dy, dz, drx, dry, drz; - - if (nMotionEvents == 0) - { - dx = 0; - dy = 0; - dz = 0; - drx = 0; - dry = 0; - drz = 0; - } - else - { - dx = motionDataArray[0]; - dy = motionDataArray[1]; - dz = motionDataArray[2]; - drx = motionDataArray[3]; - dry = motionDataArray[4]; - drz = motionDataArray[5]; - } - - motionDataArray[0] = -navEvent.motion.x; - motionDataArray[1] = -navEvent.motion.z; - motionDataArray[2] = -navEvent.motion.y; - motionDataArray[3] = -navEvent.motion.rx; - motionDataArray[4] = -navEvent.motion.rz; - motionDataArray[5] = -navEvent.motion.ry; - - motionDataArray[0] += dx; - motionDataArray[1] += dy; - motionDataArray[2] += dz; - motionDataArray[3] += drx; - motionDataArray[4] += dry; - motionDataArray[5] += drz; - - /* - Send a self addressed flush event through the window system. This will - trigger a Spaceball event if FreeCAD is ready to do so. - */ - nMotionEvents++; - XClientMessageEvent flushEvent; - - flushEvent.display = display; - flushEvent.window = event->xclient.window; - flushEvent.type = ClientMessage; - flushEvent.format = 8; - flushEvent.message_type = motion_flush_event; - - XSendEvent (display, flushEvent.window, False, 0, (XEvent*)&flushEvent); // siehe spnavd, False, 0 - - return true; - } - - if (navEvent.type == SPNAV_EVENT_BUTTON) - { - mainApp->postButtonEvent(navEvent.button.bnum, navEvent.button.press); - return true; - } - - Base::Console().Log("Unknown spaceball event\n"); - return true; -} -#endif // if/else QT_VERSION >= 0x050000 - #include "3Dconnexion/moc_GuiNativeEventLinuxX11.cpp" diff --git a/src/Gui/3Dconnexion/GuiNativeEventWin32.cpp b/src/Gui/3Dconnexion/GuiNativeEventWin32.cpp index 2fcf5df8a6..9029309eda 100644 --- a/src/Gui/3Dconnexion/GuiNativeEventWin32.cpp +++ b/src/Gui/3Dconnexion/GuiNativeEventWin32.cpp @@ -45,9 +45,7 @@ http://www.3dconnexion.com/forum/viewtopic.php?f=19&t=4968&sid=72c018bdcf0e6edc9 #include #include #include "GuiApplicationNativeEventAware.h" -#if QT_VERSION >= 0x050000 - #include "GuiRawInputEventFilter.h" -#endif // #if QT_VERSION >= 0x050000 +#include "GuiRawInputEventFilter.h" Gui::GuiNativeEvent* Gui::GuiNativeEvent::gMouseInput = 0; @@ -277,12 +275,8 @@ void Gui::GuiNativeEvent::initSpaceball(QMainWindow *mainWindow) if (InitializeRawInput((HWND)mainWindow->winId())) { gMouseInput = this; -#if QT_VERSION >= 0x050000 qApp->installNativeEventFilter( new Gui::RawInputEventFilter(Gui::GuiNativeEvent::RawInputEventFilter)); -#else - qApp->setEventFilter(Gui::GuiNativeEvent::RawInputEventFilter); -#endif Base::Console().Log("3Dconnexion device initialized.\n"); } else { diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp index 132c6f6218..3c08f1f89b 100644 --- a/src/Gui/Application.cpp +++ b/src/Gui/Application.cpp @@ -1745,6 +1745,7 @@ void setCategoryFilterRules() stream << "qt.qpa.xcb.warning=false\n"; stream << "qt.qpa.mime.warning=false\n"; stream << "qt.svg.warning=false\n"; + stream << "qt.xkb.compose.warning=false\n"; stream.flush(); QLoggingCategory::setFilterRules(filter); } diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index bd08153797..2d42991bda 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -666,6 +666,7 @@ SET(Editor_CPP_SRCS PythonConsole.cpp PythonConsolePy.cpp PythonDebugger.cpp + PythonTracing.cpp PythonEditor.cpp SyntaxHighlighter.cpp TextEdit.cpp @@ -677,6 +678,7 @@ SET(Editor_HPP_SRCS PythonConsole.h PythonConsolePy.h PythonDebugger.h + PythonTracing.h PythonEditor.h SyntaxHighlighter.h TextEdit.h diff --git a/src/Gui/PreferencePages/DlgSettingsPythonConsole.cpp b/src/Gui/PreferencePages/DlgSettingsPythonConsole.cpp index 6e59fad4ca..0734266741 100644 --- a/src/Gui/PreferencePages/DlgSettingsPythonConsole.cpp +++ b/src/Gui/PreferencePages/DlgSettingsPythonConsole.cpp @@ -44,6 +44,7 @@ void DlgSettingsPythonConsole::saveSettings() ui->PythonWordWrap->onSave(); ui->PythonBlockCursor->onSave(); ui->PythonSaveHistory->onSave(); + ui->ProfilerInterval->onSave(); } void DlgSettingsPythonConsole::loadSettings() @@ -51,14 +52,15 @@ void DlgSettingsPythonConsole::loadSettings() ui->PythonWordWrap->onRestore(); ui->PythonBlockCursor->onRestore(); ui->PythonSaveHistory->onRestore(); + ui->ProfilerInterval->onRestore(); } -void DlgSettingsPythonConsole::changeEvent(QEvent *e) +void DlgSettingsPythonConsole::changeEvent(QEvent* event) { - if (e->type() == QEvent::LanguageChange) { + if (event->type() == QEvent::LanguageChange) { ui->retranslateUi(this); } - QWidget::changeEvent(e); + QWidget::changeEvent(event); } #include "moc_DlgSettingsPythonConsole.cpp" diff --git a/src/Gui/PreferencePages/DlgSettingsPythonConsole.ui b/src/Gui/PreferencePages/DlgSettingsPythonConsole.ui index e72f80f3cf..b7f2ac20b6 100644 --- a/src/Gui/PreferencePages/DlgSettingsPythonConsole.ui +++ b/src/Gui/PreferencePages/DlgSettingsPythonConsole.ui @@ -78,6 +78,35 @@ horizontal space in Python console + + + + Python profiler interval (milliseconds): + + + + + + + The interval at which the profiler runs when there's Python code running (to keep the GUI responding). Set to 0 to disable. + + + 0 + + + 5000 + + + 200 + + + ProfilerInterval + + + PythonConsole + + + @@ -102,6 +131,11 @@ horizontal space in Python console QCheckBox
Gui/PrefWidgets.h
+ + Gui::PrefSpinBox + QSpinBox +
Gui/PrefWidgets.h
+
diff --git a/src/Gui/PythonConsole.cpp b/src/Gui/PythonConsole.cpp index 588940fd67..718e79cf73 100644 --- a/src/Gui/PythonConsole.cpp +++ b/src/Gui/PythonConsole.cpp @@ -32,6 +32,7 @@ # include # include # include +# include # include #endif @@ -40,6 +41,7 @@ #include "PythonConsole.h" #include "PythonConsolePy.h" +#include "PythonTracing.h" #include "Application.h" #include "CallTips.h" #include "FileDialog.h" @@ -77,9 +79,8 @@ inline bool cursorBeyond( const QTextCursor &cursor, const QTextCursor &limit, i if (cursor.hasSelection()) { return (cursor.selectionStart() >= pos && cursor.selectionEnd() >= pos); } - else { - return cursor.position() >= (pos + shift); - } + + return cursor.position() >= (pos + shift); } struct PythonConsoleP @@ -87,9 +88,9 @@ struct PythonConsoleP enum Output {Error = 20, Message = 21}; enum CopyType {Normal, History, Command}; CopyType type; - PyObject *_stdoutPy, *_stderrPy, *_stdinPy, *_stdin; - InteractiveInterpreter* interpreter; - CallTipsList* callTipsList; + PyObject *_stdoutPy=nullptr, *_stderrPy=nullptr, *_stdinPy=nullptr, *_stdin=nullptr; + InteractiveInterpreter* interpreter=nullptr; + CallTipsList* callTipsList=nullptr; ConsoleHistory history; QString output, error, info, historyFile; QStringList statements; @@ -99,12 +100,6 @@ struct PythonConsoleP PythonConsoleP() { type = Normal; - _stdoutPy = nullptr; - _stderrPy = nullptr; - _stdinPy = nullptr; - _stdin = nullptr; - interpreter = nullptr; - callTipsList = nullptr; interactive = false; historyFile = QString::fromUtf8((App::Application::getUserAppDataDir() + "PythonHistory.log").c_str()); colormap[QLatin1String("Text")] = qApp->palette().windowText().color(); @@ -123,12 +118,15 @@ struct PythonConsoleP colormap[QLatin1String("Python error")] = Qt::red; } }; + struct InteractiveInterpreterP { - PyObject* interpreter; - PyObject* sysmodule; + PyObject* interpreter{nullptr}; + PyObject* sysmodule{nullptr}; QStringList buffer; + PythonTracing trace; }; + } // namespace Gui InteractiveInterpreter::InteractiveInterpreter() @@ -302,6 +300,16 @@ bool InteractiveInterpreter::runSource(const char* source) const return false; } +bool InteractiveInterpreter::isOccupied() const +{ + return d->trace.isActive(); +} + +bool InteractiveInterpreter::interrupt() const +{ + return d->trace.interrupt(); +} + /* Execute a code object. * * When an exception occurs, a traceback is displayed. @@ -309,6 +317,13 @@ bool InteractiveInterpreter::runSource(const char* source) const */ void InteractiveInterpreter::runCode(PyCodeObject* code) const { + if (isOccupied()) { + return; + } + + d->trace.fetchFromSettings(); + PythonTracingLocker tracelock(d->trace); + Base::PyGILStateLocker lock; PyObject *module, *dict, *presult; /* "exec code in d, d" */ module = PyImport_AddModule("__main__"); /* get module, init python */ @@ -485,6 +500,10 @@ PythonConsole::PythonConsole(QWidget *parent) d->output = d->info; printPrompt(PythonConsole::Complete); loadHistory(); + + flusher = new QTimer(this); + connect(flusher, &QTimer::timeout, this, &PythonConsole::flushOutput); + flusher->start(100); } /** Destroys the object and frees any allocated resources */ @@ -565,6 +584,12 @@ void PythonConsole::keyPressEvent(QKeyEvent * e) QTextCursor cursor = this->textCursor(); QTextCursor inputLineBegin = this->inputBegin(); + if (e->key() == Qt::Key_C && e->modifiers() == Qt::ControlModifier) { + if (d->interpreter->interrupt()) { + return; + } + } + if (!cursorBeyond( cursor, inputLineBegin )) { /** @@ -740,6 +765,15 @@ void PythonConsole::onFlush() printPrompt(PythonConsole::Flush); } +void PythonConsole::flushOutput() +{ + if (d->interpreter->isOccupied()) { + if (d->output.length() > 0 || d->error.length() > 0) { + printPrompt(PythonConsole::Complete); + } + } +} + /** Prints the ps1 prompt (>>> ) for complete and ps2 prompt (... ) for * incomplete commands to the console window. */ @@ -830,6 +864,11 @@ void PythonConsole::runSource(const QString& line) return; } + if (d->interpreter->isOccupied()) { + insertPythonError(QString::fromLatin1("Previous command still running!")); + return; + } + bool incomplete = false; Base::PyGILStateLocker lock; PyObject* default_stdout = PySys_GetObject("stdout"); diff --git a/src/Gui/PythonConsole.h b/src/Gui/PythonConsole.h index 1db269840e..1375334cd5 100644 --- a/src/Gui/PythonConsole.h +++ b/src/Gui/PythonConsole.h @@ -24,6 +24,7 @@ #define GUI_PYTHONCONSOLE_H #include +#include #include "PythonEditor.h" @@ -42,6 +43,9 @@ public: InteractiveInterpreter(); ~InteractiveInterpreter(); + bool isOccupied() const; + bool interrupt() const; + bool push(const char*); int compileCommand(const char*) const; bool hasPendingInput( ) const; @@ -151,6 +155,7 @@ private: void appendOutput(const QString&, int); void loadHistory() const; void saveHistory() const; + void flushOutput(); Q_SIGNALS: void pendingSource( ); @@ -158,13 +163,13 @@ Q_SIGNALS: private: struct PythonConsoleP* d; + PythonConsoleHighlighter* pythonSyntax{nullptr}; + QString *_sourceDrain{nullptr}; + QString _historyFile; + QTimer *flusher{nullptr}; + friend class PythonStdout; friend class PythonStderr; - -private: - PythonConsoleHighlighter* pythonSyntax; - QString *_sourceDrain; - QString _historyFile; }; /** diff --git a/src/Gui/PythonTracing.cpp b/src/Gui/PythonTracing.cpp new file mode 100644 index 0000000000..d128f1d308 --- /dev/null +++ b/src/Gui/PythonTracing.cpp @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later + +/*************************************************************************** + * Copyright (c) 2023 Werner Mayer * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + **************************************************************************/ + +#include "PreCompiled.h" +#ifndef _PreComp_ +#include +#include +#endif + +#include "PythonTracing.h" +#include + +using namespace Gui; + +struct PythonTracing::Private +{ + bool active{false}; + int timeout{200}; //NOLINT + + // NOLINTBEGIN + static int profilerInterval; + static bool profilerDisabled; + // NOLINTEND +}; + +// NOLINTBEGIN +int PythonTracing::Private::profilerInterval = 200; +bool PythonTracing::Private::profilerDisabled = false; +// NOLINTEND + +PythonTracing::PythonTracing() + : d{std::make_unique()} +{ +} + +PythonTracing::~PythonTracing() = default; + +bool PythonTracing::isActive() const +{ + return d->active; +} + +void PythonTracing::activate() +{ + d->active = true; + setPythonTraceEnabled(true); +} + +void PythonTracing::deactivate() +{ + d->active = false; + setPythonTraceEnabled(false); +} + +void PythonTracing::fetchFromSettings() +{ + const long defaultTimeout = 200; + + auto parameterGroup = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/PythonConsole"); + int interval = static_cast(parameterGroup->GetInt("ProfilerInterval", defaultTimeout)); + setTimeout(interval); +} + +bool PythonTracing::interrupt() const +{ + if (isActive()) { + PyErr_SetInterrupt(); + return true; + } + + return false; +} + +void PythonTracing::setTimeout(int ms) +{ + d->timeout = ms; +} + +int PythonTracing::timeout() const +{ + return d->timeout; +} + +void PythonTracing::setPythonTraceEnabled(bool enabled) const +{ + Py_tracefunc trace = nullptr; + if (enabled && timeout() > 0) { + Private::profilerInterval = timeout(); + trace = &tracer_callback; + } + else { + Private::profilerDisabled = true; + } + + PyEval_SetTrace(trace, nullptr); +} + +/* + * This callback ensures that Qt runs its event loop (i.e. updates the GUI, processes keyboard and + * mouse events, etc.) at least every 200 ms, even when there is long-running Python code on the + * main thread. It is registered as the global trace function of the Python environment. + */ +int PythonTracing::tracer_callback(PyObject *obj, PyFrameObject *frame, int what, PyObject *arg) +{ + Q_UNUSED(obj) + Q_UNUSED(frame) + Q_UNUSED(what) + Q_UNUSED(arg) + + static QTime lastCalledTime = QTime::currentTime(); + QTime currTime = QTime::currentTime(); + + // if previous code object was executed + if (Private::profilerDisabled) { + Private::profilerDisabled = false; + lastCalledTime = currTime; + } + + int ms = lastCalledTime.msecsTo(currTime); + + if (ms >= Private::profilerInterval) { + lastCalledTime = currTime; + QGuiApplication::processEvents(); + } + + return 0; +} + +// ------------------------------------------------------------------------------------------------ + +PythonTracingLocker::PythonTracingLocker(PythonTracing& trace) + : trace{trace} +{ + trace.activate(); +} + +PythonTracingLocker::~PythonTracingLocker() +{ + trace.deactivate(); +} diff --git a/src/Gui/PythonTracing.h b/src/Gui/PythonTracing.h new file mode 100644 index 0000000000..8f09cef301 --- /dev/null +++ b/src/Gui/PythonTracing.h @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later + +/*************************************************************************** + * Copyright (c) 2023 Werner Mayer * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + **************************************************************************/ + +#ifndef GUI_PYTHONTRACING_H +#define GUI_PYTHONTRACING_H + +#include +#include +#include +#include + + +namespace Gui { + +class GuiExport PythonTracing +{ +public: + PythonTracing(); + ~PythonTracing(); + + PythonTracing(const PythonTracing&) = delete; + PythonTracing(PythonTracing&&) = delete; + PythonTracing& operator = (const PythonTracing&) = delete; + PythonTracing& operator = (PythonTracing&&) = delete; + + /*! + * \brief isActive + * Returns true if the tracing is active, false otherwise. + * \return + */ + bool isActive() const; + /*! + * \brief activate + * Activates the Python tracing. + */ + void activate(); + /*! + * \brief deactivate + * Deactivates the Python tracing. + */ + void deactivate(); + /*! + * \brief fetchFromSettings + * Fetch parameters from user settings. + */ + void fetchFromSettings(); + /*! + * \brief interrupt + * If the tracing is enabled it interrupts the Python interpreter. + * True is returned if the tracing is active, false otherwise. + */ + bool interrupt() const; + /*! + * \brief setTimeout + * Sets the interval after which the Qt event loop will be processed. + */ + void setTimeout(int ms); + /*! + * \brief timeout + * \return the timeout of processing the event loop. + */ + int timeout() const; + +private: + void setPythonTraceEnabled(bool enabled) const; + static int tracer_callback(PyObject *obj, PyFrameObject *frame, int what, PyObject *arg); + +private: + struct Private; + std::unique_ptr d; +}; + +class GuiExport PythonTracingLocker +{ +public: + /*! + * \brief PythonTracingLocker + * Activates the passed tracing object. + * \param trace + */ + explicit PythonTracingLocker(PythonTracing& trace); + /*! + * Deactivates the tracing object. + */ + ~PythonTracingLocker(); + + PythonTracingLocker(const PythonTracingLocker&) = delete; + PythonTracingLocker(PythonTracingLocker&&) = delete; + PythonTracingLocker& operator = (const PythonTracingLocker&) = delete; + PythonTracingLocker& operator = (PythonTracingLocker&&) = delete; + +private: + PythonTracing& trace; +}; + +} // namespace Gui + +#endif // GUI_PYTHONTRACING_H diff --git a/src/Mod/Draft/draftguitools/gui_trackers.py b/src/Mod/Draft/draftguitools/gui_trackers.py index 9cf06de6f9..5dd232932b 100644 --- a/src/Mod/Draft/draftguitools/gui_trackers.py +++ b/src/Mod/Draft/draftguitools/gui_trackers.py @@ -530,7 +530,7 @@ class arcTracker(Tracker): """An arc tracker.""" def __init__(self, dotted=False, scolor=None, swidth=None, - start=0, end=math.pi*2, normal=None): + start=0, end=math.pi*2): self.circle = None self.startangle = math.degrees(start) self.endangle = math.degrees(end) @@ -538,10 +538,11 @@ class arcTracker(Tracker): self.trans.translation.setValue([0, 0, 0]) self.sep = coin.SoSeparator() self.autoinvert = True - if normal: - self.normal = normal - else: - self.normal = FreeCAD.DraftWorkingPlane.axis + self.normal = FreeCAD.DraftWorkingPlane.axis + ang = DraftVecUtils.angle(self.getDeviation(), + FreeCAD.DraftWorkingPlane.u, + self.normal) + self.ang_offset = math.degrees(ang) self.recompute() super().__init__(dotted, scolor, swidth, [self.trans, self.sep], name="arcTracker") @@ -578,10 +579,7 @@ class arcTracker(Tracker): """Return the angle of a given vector in radians.""" c = self.trans.translation.getValue() center = Vector(c[0], c[1], c[2]) - rad = pt.sub(center) - a = DraftVecUtils.angle(rad, self.getDeviation(), self.normal) - # print(a) - return a + return DraftVecUtils.angle(self.getDeviation(), pt.sub(center), self.normal) def getAngles(self): """Return the start and end angles in degrees.""" @@ -589,11 +587,11 @@ class arcTracker(Tracker): def setStartPoint(self, pt): """Set the start angle from a point.""" - self.setStartAngle(-self.getAngle(pt)) + self.setStartAngle(self.getAngle(pt)) def setEndPoint(self, pt): """Set the end angle from a point.""" - self.setEndAngle(-self.getAngle(pt)) + self.setEndAngle(self.getAngle(pt)) def setApertureAngle(self, ang): """Set the end angle by giving the aperture angle.""" @@ -622,12 +620,16 @@ class arcTracker(Tracker): if self.circle: self.sep.removeChild(self.circle) self.circle = None - if (self.endangle < self.startangle) or not self.autoinvert: - c = Part.makeCircle(1, Vector(0, 0, 0), - self.normal, self.endangle, self.startangle) + if self.autoinvert is False: + ang_sta = self.endangle + ang_end = self.startangle + elif self.endangle < self.startangle: + ang_sta = self.endangle + self.ang_offset + ang_end = self.startangle + self.ang_offset else: - c = Part.makeCircle(1, Vector(0, 0, 0), - self.normal, self.startangle, self.endangle) + ang_sta = self.startangle + self.ang_offset + ang_end = self.endangle + self.ang_offset + c = Part.makeCircle(1, Vector(0, 0, 0), self.normal, ang_sta, ang_end) buf = c.writeInventor(2, 0.01) try: ivin = coin.SoInput() @@ -779,7 +781,7 @@ class ghostTracker(Tracker): def setMatrix(self, matrix): """Set the transformation matrix. - + The 4th column of the matrix (the position) is ignored. """ m = coin.SbMatrix(matrix.A11, matrix.A12, matrix.A13, matrix.A14, diff --git a/src/Mod/Fem/App/FemPostFilter.cpp b/src/Mod/Fem/App/FemPostFilter.cpp index ff9fb3c9bd..aad66d32e0 100644 --- a/src/Mod/Fem/App/FemPostFilter.cpp +++ b/src/Mod/Fem/App/FemPostFilter.cpp @@ -162,7 +162,7 @@ FemPostDataAlongLineFilter::FemPostDataAlongLineFilter() m_probe->SetPassPointArrays(1); m_probe->SetPassCellArrays(1); // needs vtk > 6.1 -#if (VTK_MAJOR_VERSION > 6) || (VTK_MINOR_VERSION > 1) +#if (VTK_MAJOR_VERSION > 6) && (VTK_MINOR_VERSION > 1) m_probe->ComputeToleranceOff(); m_probe->SetTolerance(0.01); #endif @@ -311,7 +311,7 @@ FemPostDataAtPointFilter::FemPostDataAtPointFilter() m_probe->SetPassPointArrays(1); m_probe->SetPassCellArrays(1); // needs vtk > 6.1 -#if (VTK_MAJOR_VERSION > 6) || (VTK_MINOR_VERSION > 1) +#if (VTK_MAJOR_VERSION > 6) && (VTK_MINOR_VERSION > 1) m_probe->ComputeToleranceOff(); m_probe->SetTolerance(0.01); #endif diff --git a/src/Mod/Fem/Gui/DlgSettingsFemGeneral.ui b/src/Mod/Fem/Gui/DlgSettingsFemGeneral.ui index 63ec752603..ea264c56f8 100644 --- a/src/Mod/Fem/Gui/DlgSettingsFemGeneral.ui +++ b/src/Mod/Fem/Gui/DlgSettingsFemGeneral.ui @@ -69,7 +69,7 @@ - Let the application manage (create, delete) the working directories for all solver. Use temporary directories. + Let the application manage (create, delete) the working directories for all solvers. Use temporary directories. true diff --git a/src/Mod/Part/Gui/DlgScale.cpp b/src/Mod/Part/Gui/DlgScale.cpp index 05fbdf1aa5..3666740351 100644 --- a/src/Mod/Part/Gui/DlgScale.cpp +++ b/src/Mod/Part/Gui/DlgScale.cpp @@ -68,6 +68,12 @@ DlgScale::DlgScale(QWidget* parent, Qt::WindowFlags fl) ui->dsbYScale->setDecimals(Base::UnitsApi::getDecimals()); ui->dsbZScale->setDecimals(Base::UnitsApi::getDecimals()); findShapes(); + + // this will mark as selected all the items in treeWidget that are selected in the document + Gui::ItemViewSelection sel(ui->treeWidget); + sel.applyFrom(Gui::Selection().getObjectsOfType(Part::Feature::getClassTypeId())); + sel.applyFrom(Gui::Selection().getObjectsOfType(App::Link::getClassTypeId())); + sel.applyFrom(Gui::Selection().getObjectsOfType(App::Part::getClassTypeId())); } void DlgScale::setupConnections() @@ -102,15 +108,8 @@ void DlgScale::onUniformScaleToggled(bool state) } } -App::DocumentObject& DlgScale::getShapeToScale() const -{ -// Base::Console().Message("DS::getShapeToScale()\n"); - std::vector objs = this->getShapesToScale(); - if (objs.empty()) - throw Base::ValueError("No shapes selected"); - return *(objs[0]); -} - +//! find all the scalable objects in the active document and load them into the +//! list widget void DlgScale::findShapes() { // Base::Console().Message("DS::findShapes()\n"); @@ -141,6 +140,7 @@ void DlgScale::findShapes() } } +//! return true if shape can be scaled. bool DlgScale::canScale(const TopoDS_Shape& shape) const { if (shape.IsNull()) { @@ -156,11 +156,13 @@ bool DlgScale::canScale(const TopoDS_Shape& shape) const if (type == TopAbs_COMPOUND || type == TopAbs_COMPSOLID) { TopExp_Explorer xp; - xp.Init(shape, TopAbs_SHAPE); + xp.Init(shape, TopAbs_EDGE); for ( ; xp.More() ; xp.Next()) { - // there is at least 1 sub shape inside the compound + // there is at least 1 edge inside the compound, so as long as it isn't null, + // we can scale this shape. We can stop looking as soon as we find a non-null + // edge. if (!xp.Current().IsNull()) { - // found a non-null shape + // found a non-null edge return true; } } @@ -186,6 +188,7 @@ void DlgScale::accept() }; } +// create a FeatureScale for each scalable object void DlgScale::apply() { // Base::Console().Message("DS::apply()\n"); @@ -264,6 +267,8 @@ void DlgScale::reject() QDialog::reject(); } +//! retrieve the document objects associated with the selected items in the list +//! widget std::vector DlgScale::getShapesToScale() const { // Base::Console().Message("DS::getShapesToScale()\n"); @@ -282,6 +287,8 @@ std::vector DlgScale::getShapesToScale() const return objects; } +//! return true if at least one item in the list widget corresponds to an +//! available document object in the document bool DlgScale::validate() { QList items = ui->treeWidget->selectedItems(); @@ -299,6 +306,7 @@ bool DlgScale::validate() return !objects.empty(); } +//! update a FeatureScale with the parameters from the UI void DlgScale::writeParametersToFeature(App::DocumentObject &feature, App::DocumentObject* base) const { // Base::Console().Message("DS::writeParametersToFeature()\n"); diff --git a/src/Mod/Sandbox/App/AppSandbox.cpp b/src/Mod/Sandbox/App/AppSandbox.cpp index 37b569ce65..4618589aa8 100644 --- a/src/Mod/Sandbox/App/AppSandbox.cpp +++ b/src/Mod/Sandbox/App/AppSandbox.cpp @@ -146,7 +146,7 @@ public: return genericSetAttro( name_, value ); } } - virtual int sequence_length() + virtual PyCxx_ssize_t sequence_length() { // len(x) return m_array.size(); diff --git a/src/Mod/Sandbox/App/DocumentThread.cpp b/src/Mod/Sandbox/App/DocumentThread.cpp index ecec31d779..b1a68a867f 100644 --- a/src/Mod/Sandbox/App/DocumentThread.cpp +++ b/src/Mod/Sandbox/App/DocumentThread.cpp @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -88,7 +89,7 @@ void WorkerThread::run() // -------------------------------------- -QMutex PythonThread::mutex(QMutex::Recursive); +QRecursiveMutex PythonThread::mutex; PythonThread::PythonThread(QObject* parent) : QThread(parent) diff --git a/src/Mod/Sandbox/App/DocumentThread.h b/src/Mod/Sandbox/App/DocumentThread.h index b8329c38c8..aa607d86a2 100644 --- a/src/Mod/Sandbox/App/DocumentThread.h +++ b/src/Mod/Sandbox/App/DocumentThread.h @@ -25,7 +25,7 @@ #define SANDBOX_DOCUMENTTHREAD_H #include -#include +#include #include #include @@ -63,7 +63,7 @@ public: protected: void run(); - static QMutex mutex; + static QRecursiveMutex mutex; }; class SandboxAppExport MeshLoaderThread : public QThread diff --git a/src/Mod/Sandbox/Gui/CMakeLists.txt b/src/Mod/Sandbox/Gui/CMakeLists.txt index 67431d322b..4476da5eaf 100644 --- a/src/Mod/Sandbox/Gui/CMakeLists.txt +++ b/src/Mod/Sandbox/Gui/CMakeLists.txt @@ -37,14 +37,7 @@ set(SandboxGui_MOC_HDRS GLGraphicsView.h ) -fc_wrap_cpp(SandboxGui_MOC_SRCS ${SandboxGui_MOC_HDRS}) -SOURCE_GROUP("Moc" FILES ${SandboxGui_MOC_SRCS}) - -if(BUILD_QT5) - qt5_add_resources(Resource_SRCS Resources/Sandbox.qrc) -else() - qt4_add_resources(Resource_SRCS Resources/Sandbox.qrc) -endif() +qt_add_resources(Resource_SRCS Resources/Sandbox.qrc) SET(Resource_SRCS ${Resource_SRCS} Resources/Sandbox.qrc diff --git a/src/Mod/Sandbox/Gui/Command.cpp b/src/Mod/Sandbox/Gui/Command.cpp index 0f034ec871..5709af9019 100644 --- a/src/Mod/Sandbox/Gui/Command.cpp +++ b/src/Mod/Sandbox/Gui/Command.cpp @@ -68,6 +68,7 @@ #include #include #include +#include #include #include #include @@ -933,7 +934,7 @@ void CmdTestGrabWidget::activated(int) { QCalendarWidget* c = new QCalendarWidget(); c->hide(); - QPixmap p = QPixmap::grabWidget(c, c->rect()); + QPixmap p = c->grab(c->rect()); QLabel* label = new QLabel(); label->resize(c->size()); label->setPixmap(p); @@ -1055,7 +1056,7 @@ void CmdTestImageNode::activated(int) QString text = QString::fromLatin1("Distance: 2.7jgiorjgor84mm"); QFont font; QFontMetrics fm(font); - int w = fm.width(text); + int w = Gui::QtTools::horizontalAdvance(fm, text); int h = fm.height(); diff --git a/src/Mod/Sandbox/Gui/GLGraphicsView.cpp b/src/Mod/Sandbox/Gui/GLGraphicsView.cpp index b3ee4eb1ac..6cae14de5f 100644 --- a/src/Mod/Sandbox/Gui/GLGraphicsView.cpp +++ b/src/Mod/Sandbox/Gui/GLGraphicsView.cpp @@ -48,7 +48,6 @@ #include #include #include -#include #include #include #include @@ -57,6 +56,7 @@ #include #include "GLGraphicsView.h" +#include #include #include @@ -239,10 +239,12 @@ SceneEventFilter::eventFilter(QObject *, QEvent * qevent) } case QEvent::GraphicsSceneWheel: { +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) QGraphicsSceneWheelEvent* ev = static_cast(qevent); sceneev.reset(new QWheelEvent(ev->pos().toPoint(), ev->delta(), ev->buttons(), ev->modifiers(), ev->orientation())); qevent = sceneev.get(); +#endif break; } case QEvent::GraphicsSceneResize: @@ -351,7 +353,9 @@ GraphicsScene::GraphicsScene() pos += QPointF(0, 10 + rect.height()); } +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) m_time.start(); +#endif sorendermanager = new SoRenderManager; sorendermanager->setAutoClipping(SoRenderManager::VARIABLE_NEAR_PLANE); @@ -572,14 +576,18 @@ void GraphicsScene::drawBackground(QPainter *painter, const QRectF &) return; } +#if 0 glViewport(0, 0, width(), height()); /**/ glClearColor(m_backgroundColor.redF(), m_backgroundColor.greenF(), m_backgroundColor.blueF(), 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +#endif +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) const int delta = m_time.elapsed() - m_lastTime; m_lastTime += delta; +#endif sorendermanager->render(true/*PRIVATE(this)->clearwindow*/, @@ -625,7 +633,9 @@ void GraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event) if (event->isAccepted()) return; +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) m_mouseEventTime = m_time.elapsed(); +#endif event->accept(); } @@ -654,10 +664,12 @@ GraphicsView3D::GraphicsView3D(Gui::Document* doc, QWidget* parent) : Gui::MDIView(doc, parent), m_scene(new GraphicsScene()), m_view(new GraphicsView) { m_view->installEventFilter(m_scene->getEventFilter()); - QGLFormat f; +#if 0 + QtGLFormat f; f.setSampleBuffers(true); f.setSamples(8); m_view->setViewport(new QGLWidget(f)); +#endif m_view->setViewportUpdateMode(QGraphicsView::FullViewportUpdate); m_view->setScene(m_scene); m_scene->setNavigationModeFile(QUrl(QString::fromLatin1("coin:///scxml/navigation/examiner.xml"))); @@ -698,5 +710,4 @@ void GraphicsView3D::OnChange(ParameterGrp::SubjectType &rCaller,ParameterGrp::M m_scene->setBackgroundColor(QColor::fromRgbF(r1, g1, b1)); } } - #include "moc_GLGraphicsView.cpp" diff --git a/src/Mod/Sandbox/Gui/Overlay.cpp b/src/Mod/Sandbox/Gui/Overlay.cpp index e7fa9e8f7c..61ca950f4d 100644 --- a/src/Mod/Sandbox/Gui/Overlay.cpp +++ b/src/Mod/Sandbox/Gui/Overlay.cpp @@ -63,20 +63,11 @@ public: p.drawText(200,200,QString::fromLatin1("Render to QImage")); } -#if !defined(HAVE_QT5_OPENGL) - img = QtGLWidget::convertToGLFormat(img); -#endif fbo = new QtGLFramebufferObject(v->getGLWidget()->size()); fbo->bind(); //glClear(GL_COLOR_BUFFER_BIT); fbo->release(); { -#if !defined(HAVE_QT5_OPENGL) - QPainter p(fbo); - p.setPen(Qt::white); - p.drawText(200,200,QString::fromLatin1("Render to QtGLFramebufferObject")); - p.end(); -#endif //img = fbo->toImage(); //img = QtGLWidget::convertToGLFormat(img); } @@ -626,18 +617,6 @@ void DrawingPlane::drawLineTo(const QPoint &endPoint) { Q_UNUSED(endPoint); return; -#if !defined(HAVE_QT5_OPENGL) - QPainter painter(fbo); - //QPainter painter(_pcView3D->getGLWidget()); - painter.setPen(QPen(myPenColor, myPenWidth, Qt::SolidLine, Qt::RoundCap, - Qt::RoundJoin)); - //painter.setOpacity(0.5); - //painter.drawLine(lastPoint.x(), fbo->height()-lastPoint.y(), endPoint.x(), fbo->height()-endPoint.y()); - painter.drawLine(lastPoint.x(), lastPoint.y(), endPoint.x(), endPoint.y()); - - //_pcView3D->scheduleRedraw(); - lastPoint = endPoint; -#endif } //Gui::Document* doc = Gui::Application::Instance->activeDocument(); //Gui::View3DInventorViewer* view = static_cast(doc->getActiveView())->getViewer(); diff --git a/src/Mod/Sandbox/Gui/TaskPanelView.cpp b/src/Mod/Sandbox/Gui/TaskPanelView.cpp index ad2e78b1ad..10ac3b1f5c 100644 --- a/src/Mod/Sandbox/Gui/TaskPanelView.cpp +++ b/src/Mod/Sandbox/Gui/TaskPanelView.cpp @@ -364,8 +364,6 @@ public: Q_UNUSED(MainWindow); } // retranslateUi }; -#else -#include #endif TaskPanelView::TaskPanelView(QWidget *parent) @@ -580,96 +578,6 @@ TaskPanelView::TaskPanelView(QWidget *parent) connect(ui->rbAndroidScheme, SIGNAL(toggled(bool)), androidAction, SIGNAL(toggled(bool))); func->toggle(androidAction, boost::bind(&TaskPanelView::on_rbAndroidScheme_toggled, this, bp::_1)); } -#else - setWindowTitle(QLatin1String("Task View")); - - QGridLayout* gridLayout = new QGridLayout(this); - iisTaskPanel *taskPanel = new iisTaskPanel(this); - iisTaskBox *tb1 = new iisTaskBox( - QPixmap(QString::fromLatin1(":/icons/document-save.svg")),QLatin1String("Expandable Group"),true, this); - taskPanel->addWidget(tb1); - gridLayout->addWidget(taskPanel, 0, 0, 2, 1); - - iisIconLabel *i1 = new iisIconLabel( - Gui::BitmapFactory().iconFromTheme("document-new"), QLatin1String("Create new file"), tb1); - tb1->addIconLabel(i1); - connect(i1, SIGNAL(activated()), action, SIGNAL(triggered())); - - iisIconLabel *i2 = new iisIconLabel( - Gui::BitmapFactory().iconFromTheme("document-open"), QLatin1String("Load a file"), tb1); - tb1->addIconLabel(i2); - connect(i2, SIGNAL(activated()), action, SIGNAL(triggered())); - - tb1->groupLayout()->addWidget(new QPushButton(QLatin1String("Just a button"), this)); - - iisIconLabel *i3 = new iisIconLabel( - Gui::BitmapFactory().iconFromTheme("document-save"), QLatin1String("Save current file"), tb1); - tb1->addIconLabel(i3); - - iisIconLabel *i4 = new iisIconLabel( - Gui::BitmapFactory().iconFromTheme("document-print"), QLatin1String("Print file contents"), tb1); - tb1->addIconLabel(i4); - i4->setColors(Qt::red, Qt::green, Qt::gray); - i4->setFocusPen(QPen()); - - tb1->groupLayout()->addWidget(new QPushButton(QLatin1String("Just another button"), this)); - - iisTaskBox *tb2 = new iisTaskBox( - Gui::BitmapFactory().pixmap("edit-redo"), QLatin1String("Non-expandable Group"), false, this); - taskPanel->addWidget(tb2); - - iisIconLabel *i21 = new iisIconLabel( - Gui::BitmapFactory().iconFromTheme("document-new"), QLatin1String("Create new file"), tb2); - tb2->addIconLabel(i21); - - iisIconLabel *i22 = new iisIconLabel( - Gui::BitmapFactory().iconFromTheme("document-open"), QLatin1String("Load a file"), tb2); - tb2->addIconLabel(i22); - - iisIconLabel *i23 = new iisIconLabel( - Gui::BitmapFactory().iconFromTheme("document-save"), QLatin1String("Save current file"), tb2); - tb2->addIconLabel(i23); - i23->setEnabled(false); - - iisIconLabel *i24 = new iisIconLabel( - Gui::BitmapFactory().iconFromTheme("document-print"), QLatin1String("Print file contents"), tb2); - tb2->addIconLabel(i24); - - - // Other widgets can be also added to the panel - QLabel *l1 = new QLabel(QLatin1String("Action Group without header"), this); - taskPanel->addWidget(l1); - - iisTaskGroup *tb3 = new iisTaskGroup(this); - taskPanel->addWidget(tb3); - - iisIconLabel *i31 = new iisIconLabel( - Gui::BitmapFactory().iconFromTheme("document-new"), QLatin1String("Create new file"), tb3); - tb3->addIconLabel(i31); - - QHBoxLayout *hb3 = new QHBoxLayout(); - tb3->groupLayout()->addLayout(hb3); - - iisIconLabel *i32 = new iisIconLabel( - Gui::BitmapFactory().iconFromTheme("document-open"), QLatin1String("Load a file"), tb3); - tb3->addIconLabel(i32); - hb3->addWidget(i32); - - iisIconLabel *i33 = new iisIconLabel( - Gui::BitmapFactory().iconFromTheme("document-save"), QLatin1String("Save current file"), tb3); - tb3->addIconLabel(i33); - i33->setDisabled(true); - hb3->addWidget(i33); - - iisIconLabel *i34 = new iisIconLabel( - Gui::BitmapFactory().iconFromTheme("document-print"), QLatin1String("Print file contents"), tb3); - tb3->addIconLabel(i34); - - taskPanel->addStretch(); - taskPanel->setScheme(iisWinXPTaskPanelScheme::defaultScheme()); - tb1->setScheme(iisWinXPTaskPanelScheme::defaultScheme()); - tb2->setScheme(iisWinXPTaskPanelScheme2::defaultScheme()); - tb3->setScheme(iisTaskPanelScheme::defaultScheme()); #endif } diff --git a/src/Mod/Sandbox/Gui/Workbench.cpp b/src/Mod/Sandbox/Gui/Workbench.cpp index 11a9fb9e61..baae5e1508 100644 --- a/src/Mod/Sandbox/Gui/Workbench.cpp +++ b/src/Mod/Sandbox/Gui/Workbench.cpp @@ -37,6 +37,7 @@ #include #include "Workbench.h" +#include #include #include #include @@ -61,7 +62,7 @@ Workbench::Workbench() QGridLayout* pLayout = new QGridLayout(tree); pLayout->setSpacing(0); - pLayout->setMargin (0); + pLayout->setContentsMargins(0, 0, 0, 0); pLayout->addWidget(treeWidget, 0, 0); tree->setObjectName @@ -159,8 +160,7 @@ void SoWidgetShape::GLRender(SoGLRenderAction * /*action*/) #if defined(HAVE_QT5_OPENGL) this->image = QPixmap::grabWidget(w, w->rect()).toImage(); #else - this->image = QPixmap::grabWidget(w, w->rect()).toImage(); - this->image = QtGLWidget::convertToGLFormat(this->image); + this->image = w->grab(w->rect()).toImage(); #endif glRasterPos2d(10,10); glDrawPixels(this->image.width(),this->image.height(),GL_RGBA,GL_UNSIGNED_BYTE,this->image.bits()); @@ -285,7 +285,6 @@ void SoWidgetShape::setWidget(QWidget* w) this->image = img.toImage(); #if !defined(HAVE_QT5_OPENGL) - this->image = QPixmap::grabWidget(w, w->rect()).toImage(); - this->image = QtGLWidget::convertToGLFormat(this->image); + this->image = w->grab(w->rect()).toImage(); #endif } diff --git a/src/Mod/Tux/CMakeLists.txt b/src/Mod/Tux/CMakeLists.txt index 656e883fc2..78995ffec2 100644 --- a/src/Mod/Tux/CMakeLists.txt +++ b/src/Mod/Tux/CMakeLists.txt @@ -30,4 +30,3 @@ INSTALL( DESTINATION Mod/Tux ) - diff --git a/src/Mod/Tux/InitGui.py b/src/Mod/Tux/InitGui.py index 86e1c49dcf..e02e7da59a 100644 --- a/src/Mod/Tux/InitGui.py +++ b/src/Mod/Tux/InitGui.py @@ -33,4 +33,3 @@ if p.GetGroup("PersistentToolbars").GetBool("Enabled", 1): import PersistentToolbarsGui else: pass - diff --git a/src/Mod/Tux/NavigationIndicatorGui.py b/src/Mod/Tux/NavigationIndicatorGui.py index 243a6a8d89..e20c0be897 100644 --- a/src/Mod/Tux/NavigationIndicatorGui.py +++ b/src/Mod/Tux/NavigationIndicatorGui.py @@ -36,7 +36,9 @@ try: def translate(context, text): "convenience function for Qt 4 translator" return QtGui.QApplication.translate(context, text, None, _encoding) + except AttributeError: + def translate(context, text): "convenience function for Qt 5 translator" return QtGui.QApplication.translate(context, text, None) @@ -44,6 +46,7 @@ except AttributeError: class IndicatorButton(QtGui.QPushButton): """Detect language change events.""" + def __init__(self, parent=None): super(IndicatorButton, self).__init__() @@ -56,7 +59,7 @@ class IndicatorButton(QtGui.QPushButton): return super(IndicatorButton, self).changeEvent(event) def onChange(self, paramGrp, param): - if(param == "NavigationStyle"): + if param == "NavigationStyle": setCurrent() @@ -78,14 +81,27 @@ def retranslateUi(): t0 = translate("NavigationIndicator", "Navigation style not recognized.") global t1 - t1 = "

Blender " + text06 + """

+ t1 = ( + "

Blender " + + text06 + + """

- - - - - + + + + + @@ -95,17 +111,35 @@ def retranslateUi():
""" + text01 + """""" + text02 + """""" + text03 + """""" + text04 + """""" + text04 + """""" + + text01 + + """""" + + text02 + + """""" + + text03 + + """""" + + text04 + + """""" + + text04 + + """
- """ + text08 + ": " + text10 + "

" + """ + + text08 + + ": " + + text10 + + "

" + ) global t2 - t2 = "

CAD " + text06 + """

+ t2 = ( + "

CAD " + + text06 + + """

- - - - - + + + + + @@ -115,18 +149,38 @@ def retranslateUi():
""" + text01 + """""" + text02 + """""" + text03 + """""" + text03 + """""" + text04 + """""" + + text01 + + """""" + + text02 + + """""" + + text03 + + """""" + + text03 + + """""" + + text04 + + """
- """ + text08 + ": " + text10 + "

" + """ + + text08 + + ": " + + text10 + + "

" + ) global t3 - t3 = "

Gesture " + text06 + """

+ t3 = ( + "

Gesture " + + text06 + + """

- - - - - - + + + + + + @@ -137,12 +191,24 @@ def retranslateUi(): - - - - - - + + + + + + @@ -153,19 +219,43 @@ def retranslateUi():
""" + text01 + """""" + text02 + """""" + text03 + """""" + text03 + """""" + text04 + """""" + text05 + """""" + + text01 + + """""" + + text02 + + """""" + + text03 + + """""" + + text03 + + """""" + + text04 + + """""" + + text05 + + """
""" + text01 + """""" + text02 + """""" + text03 + """""" + text04 + """""" + text04 + """""" + text05 + """""" + + text01 + + """""" + + text02 + + """""" + + text03 + + """""" + + text04 + + """""" + + text04 + + """""" + + text05 + + """
-

""" + text02 + ": " + text07 + """
- """ + text08 + ": " + text09 + "

" +

""" + + text02 + + ": " + + text07 + + """
+ """ + + text08 + + ": " + + text09 + + "

" + ) global t4 - t4 = "

MayaGesture " + text06 + """

+ t4 = ( + "

MayaGesture " + + text06 + + """

- - - - - - + + + + + + @@ -176,12 +266,24 @@ def retranslateUi(): - - - - - - + + + + + + @@ -192,19 +294,43 @@ def retranslateUi():
""" + text01 + """""" + text02 + """""" + text02 + """""" + text03 + """""" + text04 + """""" + text05 + """""" + + text01 + + """""" + + text02 + + """""" + + text02 + + """""" + + text03 + + """""" + + text04 + + """""" + + text05 + + """
""" + text01 + """""" + text02 + """""" + text03 + """""" + text04 + """""" + text04 + """""" + text05 + """""" + + text01 + + """""" + + text02 + + """""" + + text03 + + """""" + + text04 + + """""" + + text04 + + """""" + + text05 + + """
-

""" + text02 + ": " + text07 + """
- """ + text08 + ": " + text09 + "

" +

""" + + text02 + + ": " + + text07 + + """
+ """ + + text08 + + ": " + + text09 + + "

" + ) global t5 - t5 = "

OpenCascade " + text06 + """

+ t5 = ( + "

OpenCascade " + + text06 + + """

- - - - - - + + + + + + @@ -215,16 +341,30 @@ def retranslateUi():
""" + text01 + """""" + text02 + """""" + text02 + """""" + text03 + """""" + text04 + """""" + text04 + """""" + + text01 + + """""" + + text02 + + """""" + + text02 + + """""" + + text03 + + """""" + + text04 + + """""" + + text04 + + """
""" + ) global t6 - t6 = "

OpenInventor " + text06 + """

+ t6 = ( + "

OpenInventor " + + text06 + + """

- - - - - + + + + + @@ -234,17 +374,35 @@ def retranslateUi():
""" + text01 + """""" + text02 + """""" + text02 + """""" + text03 + """""" + text04 + """""" + + text01 + + """""" + + text02 + + """""" + + text02 + + """""" + + text03 + + """""" + + text04 + + """
- """ + text08 + ": " + text10 + "

" + """ + + text08 + + ": " + + text10 + + "

" + ) global t7 - t7 = "

OpenSCAD " + text06 + """

+ t7 = ( + "

OpenSCAD " + + text06 + + """

- - - - - + + + + + @@ -254,16 +412,30 @@ def retranslateUi():
""" + text01 + """""" + text02 + """""" + text02 + """""" + text03 + """""" + text04 + """""" + + text01 + + """""" + + text02 + + """""" + + text02 + + """""" + + text03 + + """""" + + text04 + + """
""" + ) global t8 - t8 = "

Revit " + text06 + """

+ t8 = ( + "

Revit " + + text06 + + """

- - - - - + + + + + @@ -273,16 +445,32 @@ def retranslateUi():
""" + text01 + """""" + text02 + """""" + text03 + """""" + text04 + """""" + text04 + """""" + + text01 + + """""" + + text02 + + """""" + + text03 + + """""" + + text04 + + """""" + + text04 + + """
- """ + text08 + ": " + text10 + "

" + """ + + text08 + + ": " + + text10 + + "

" + ) global t9 - t9 = "

TinkerCAD " + text06 + """

+ t9 = ( + "

TinkerCAD " + + text06 + + """

- - - - + + + + @@ -291,17 +479,33 @@ def retranslateUi():
""" + text01 + """""" + text02 + """""" + text03 + """""" + text04 + """""" + + text01 + + """""" + + text02 + + """""" + + text03 + + """""" + + text04 + + """
""" + ) global t10 - t10 = "

Touchpad " + text06 + """

+ t10 = ( + "

Touchpad " + + text06 + + """

- - - - - - + + + + + + @@ -312,11 +516,21 @@ def retranslateUi(): - - - - - + + + + + @@ -326,7 +540,12 @@ def retranslateUi():
""" + text01 + """""" + text02 + """""" + text02 + """""" + text03 + """""" + text03 + """""" + text04 + """""" + + text01 + + """""" + + text02 + + """""" + + text02 + + """""" + + text03 + + """""" + + text03 + + """""" + + text04 + + """
""" + text01 + """""" + text02 + """""" + text03 + """""" + text03 + """""" + text04 + """""" + + text01 + + """""" + + text02 + + """""" + + text03 + + """""" + + text03 + + """""" + + text04 + + """
-

""" + text02 + ": " + text07 + "

" +

""" + + text02 + + ": " + + text07 + + "

" + ) menuSettings.setTitle(translate("NavigationIndicator", "Settings")) menuOrbit.setTitle(translate("NavigationIndicator", "Orbit style")) @@ -389,7 +608,7 @@ a1.setData("Gui::BlenderNavigationStyle") a1.setObjectName("Indicator_NavigationBlender") a2 = QtGui.QAction(gStyle) -a2.setIcon(QtGui.QIcon(':/icons/NavigationCAD_dark.svg')) +a2.setIcon(QtGui.QIcon(":/icons/NavigationCAD_dark.svg")) a2.setText("CAD ") a2.setData("Gui::CADNavigationStyle") a2.setObjectName("Indicator_NavigationCAD") diff --git a/src/Mod/Tux/PersistentToolbarsGui.py b/src/Mod/Tux/PersistentToolbarsGui.py index 5f3b4c0ed1..781766d3ba 100644 --- a/src/Mod/Tux/PersistentToolbarsGui.py +++ b/src/Mod/Tux/PersistentToolbarsGui.py @@ -28,6 +28,7 @@ conectedToolbars = [] timer = QtCore.QTimer() mw = Gui.getMainWindow() + def pythonToolbars(): """Manage Python based toolbar in BIM workbench.""" @@ -85,10 +86,12 @@ def onRestore(active): # Reduce flickering. for i in toolbars: - if (i not in topRestore and - i not in leftRestore and - i not in rightRestore and - i not in bottomRestore): + if ( + i not in topRestore + and i not in leftRestore + and i not in rightRestore + and i not in bottomRestore + ): area = mw.toolBarArea(toolbars[i]) diff --git a/src/Tools/DownloadStatistics.py b/src/Tools/DownloadStatistics.py deleted file mode 100644 index d335cb52de..0000000000 --- a/src/Tools/DownloadStatistics.py +++ /dev/null @@ -1,8 +0,0 @@ -import requests - -r = requests.get("https://api.github.com/repos/FreeCAD/FreeCAD/releases") -myobj = r.json() -for p in myobj: - if "assets" in p: - for asset in p["assets"]: - print(asset["name"] + ": " + str(asset["download_count"]) + " downloads") diff --git a/src/Tools/astylerc b/src/Tools/astylerc deleted file mode 100644 index 35a82136e9..0000000000 --- a/src/Tools/astylerc +++ /dev/null @@ -1,30 +0,0 @@ -# Use these options with: astyle --options= SourceFile.cpp -# - -# Do not create a copy of the original, same as -n -suffix=none - -# set 4 spaces per indent, same as -s4 -indent=spaces=4 - -# break brackets from class and function declarations, same as -ly -brackets=linux -brackets=break-closing - -# don't break complex statements and multiple statements residing on a single line, same as -o -one-line=keep-statements - -# don't break one-line blocks, same as -O -one-line=keep-blocks - -# convert tabs into single spaces, same as -V -#convert-tabs - -# indent switch blocks, same as -K -#indent-cases - -# indent multi-line preprocessor definitions ending with a backslash, same as -w -#indent-preprocessor - -# remove space padding around parenthesis on the inside and outside, same as -U -#unpad=paren diff --git a/src/Tools/updatets.py b/src/Tools/updatets.py index 9adcf991f5..0aa18108d1 100755 --- a/src/Tools/updatets.py +++ b/src/Tools/updatets.py @@ -148,7 +148,7 @@ directories = [ "tsdir": "Gui/Resources/translations", }, { - "tsname": "Start", + "tsname": "StartPage", "workingdir": "./src/Mod/Start/", "tsdir": "Gui/Resources/translations", },