Compare commits

...

149 Commits

Author SHA1 Message Date
Maël Kerbiriou 0a49fd05a4 Gui: replace s# format unit with s* (backport from master) 2022-05-14 10:47:36 +02:00
Wanderer Fan 476ecf0919 [Import]Fix #6461 MEASUREMENT/INSUNITS 2022-02-28 02:28:48 +01:00
Yorik van Havre 8eccef1d87 Merge pull request #6444 from Roy-043/Draft-Fix-Draft_Line-Length-is-zero-bug
Draft: Fix Draft_Line Length is zero bug
2022-02-26 02:09:56 +01:00
sliptonic 7103dfd1a2 Merge pull request #5343 from Russ4262/fix/open_edge_zero_start
[Path] Fix open edge zero value start point
2022-02-18 00:38:57 +01:00
Uwe ae1b3e0d96 don't force CRC
Forcing CRC (cyclic redundancy check) is the safest method but when installing silently
one gets a shop popup about the ongoing CRC and this was reported as bug.

As solution just turn CRC on and users of the silent installer mode can omit the CRC
by setting a flag.
2022-02-13 23:57:40 +01:00
Uwe c88a1749c7 [Win installer] improve line breaks in README.md 2022-02-13 23:52:04 +01:00
Uwe 03f06f794f [Win installer] add support for logging
the installer will now write a text file 'install.log' to the installation folder of FreeCAD
2022-02-13 23:52:03 +01:00
0penBrain c453ec12e7 Base: fix bug in matrix multiplication (Python API) 2022-02-04 04:19:48 +01:00
Yorik van Havre 2065e5573d Merge pull request #5449 from mwganson/pointarray
Draft: pointarray set Count property during execute
2022-02-02 01:45:16 +01:00
Yorik van Havre d257a8a8d6 Merge pull request #5465 from Roy-043/Arch-Fix-some-dimensions-in-profiles.csv
Arch: Fix some dimensions in profiles.csv
2022-02-02 01:43:40 +01:00
Yorik van Havre 042066c55e Merge pull request #5476 from Roy-043/Draft-Fix-gui_edit.py-Y-is-zero-input-bug
Draft: Fix-gui_edit.py Y is zero input bug
2022-02-02 01:42:29 +01:00
Benjamin Bræstrup Sayoc 25ead17570 Refactor 2022-02-02 01:36:58 +01:00
Benjamin Bræstrup Sayoc e305560dd8 Only update weld dialog on directory change 2022-02-02 01:36:58 +01:00
Benjamin Bræstrup Sayoc 7dfe408686 Resizing of weld symbol selection dialog, fixes #0004386 2022-02-02 01:36:57 +01:00
Yorik van Havre fd6ff10212 Merge pull request #5388 from Roy-043/Arch-Fix-ArchWall-onBeforeChange
Arch: Fix ArchWall onBeforeChange
2022-01-27 03:27:38 +01:00
mwganson d549cff781 TopoShape::analyze() SetRunParallel(true) to do the bopcheck in parallel mode 2022-01-17 00:04:50 +01:00
mwganson a8f9f1dd42 [TechDraw] prevent crash where user has duplicated page without dependencies and then tries to remove a view from one of the pages by editing the Views property 2022-01-08 18:56:13 +01:00
mwganson 15b3cf45b1 [TechDraw] prevent crash where user duplicates page without also duplicating dependencies 2022-01-08 18:56:13 +01:00
Uwe 9af7405d5e Revert incompatible backports
(need to re-setup my build system obviously)

Revert "[PD] missing bit from a manual backport"

This reverts commit 992c0ddc64.

Revert "[PD] Hole: fix angle constraints"

This reverts commit 0dfc4aff74.

Revert "[PD] add missing hole constraint"

This reverts commit f4defb5c39.
2022-01-07 23:56:41 +01:00
Uwe 992c0ddc64 [PD] missing bit from a manual backport 2022-01-07 22:20:26 +01:00
Uwe 0dfc4aff74 [PD] Hole: fix angle constraints
- all 3 angles cannot be >= 180°
- also add missing minimum in UI for taper angle
2022-01-07 21:00:21 +01:00
Uwe f4defb5c39 [PD] add missing hole constraint
- add missing constraint for hole diameter
- add missing sets of angle constraints in the task dialog
2022-01-06 17:15:22 +01:00
Roy-043 f0d783b69f Draft: Fix importSVG.py: wrong position for certain ellipses (#5297)
Ellipses and elliptical arcs with a y radius larger than their x radius would end up in the wrong position.
2022-01-06 17:04:37 +01:00
Uwe 186bfff31c [PD] remove unnecessary Unicode characters
manual backport of commit 76c611ae
2022-01-06 04:49:53 +01:00
wmayer 03ef59bc4b Gui: move methods startDefaultEditMode() and addDefaultAction() to ViewProviderDocumentObject 2022-01-05 04:31:38 +01:00
Uwe 95d0004742 revert a not backportable fixe and its dependencies 2022-01-05 03:00:26 +01:00
wmayer 8489a55067 Base: split export/import macros from FCConfig.h and move them to FCGlobal.h
The FCGlobal.h can be included in a Global.h header file of an extension module.

The reason is that some IDEs (e.g. QtCreator) fails to detect the export/import macros when only defined in the PreCompiled.h files and thus raise a parser warning.
2022-01-05 01:57:50 +01:00
Uwe 2eb6d4748e [Win installer] upgrade year 2022-01-05 01:32:57 +01:00
wmayer b56a4292ae PD: [skip ci] add PartDesignGlobal.h with export/import macros 2022-01-05 01:08:13 +01:00
wmayer 1ffd8d553b Fix issue 0004791: DXF import fails for trivial circle 2022-01-05 01:05:51 +01:00
Roy 1caea909b5 Draft: Commands acting on subelements did not load the Draft module 2022-01-03 23:54:49 +01:00
Roy-043 d8e6fe8287 Draft: fix several issues with importAirfoilDAT.py
The importAirfoilDAT.py code could not handle several *.dat files posted in a forum topic.
2022-01-03 23:52:13 +01:00
Uwe ad6977f940 0004809: Security vulnerability in DWG import when using ODA file converter
manual backport of commit 1742d7ff
2022-01-03 23:47:04 +01:00
Syres916 b1630419fc [Gui] MainWindow New Doc camera position bugfix
See https://forum.freecadweb.org/viewtopic.php?p=556465#p556465
2022-01-03 23:35:49 +01:00
Wanderer Fan bca9684ec3 [TD]prevent touched but must be execute on DrawPage 2022-01-03 23:09:34 +01:00
sliptonic a73f442f88 Merge pull request #5306 from sliptonic/bug/4810
[PATH] fix #4810
2022-01-03 22:56:56 +01:00
wmayer 88eb350ac0 TD: [skip ci] partially fix issue 0004765 2021-12-22 01:19:01 +01:00
Uwe 454d1cbeb3 Draft: Added INSUNITS to exported DXF
fixes bug 4517

(manually backported)
2021-12-20 11:27:24 +01:00
wmayer e238e2f257 Main: [skip ci] partially fix issue 0004765: FreeCAD failed to build on MSVC with std:c++latest 2021-12-20 11:09:48 +01:00
wmayer b0ae197937 Path: [skip ci] partially fix issue 0004765: [MSVC][Build][Permissive-][std:c++latest] FreeCAD failed to build on MSVC 2021-12-20 11:08:25 +01:00
wmayer 805fb0df02 TD: [skip ci] partially fix issue 0004765 2021-12-20 11:04:40 +01:00
0penBrain 0b72f23bfb [Sketcher] Floating point computation immunity for carbon copy parallel/aligned checks 2021-12-19 19:40:41 +01:00
0penBrain dc2d9ba2f0 [Sketcher] Improve a bit XZ plane mapping by using quaternions directly 2021-12-19 19:40:41 +01:00
wmayer b4e58cea01 Web: fix storage paths of web content 2021-12-19 17:37:57 +01:00
Uwe 16ee414987 [Win installer] change naming scheme
as suggested by the release team to follow the existing naming in our releases
2021-12-13 01:18:15 +01:00
Roy a84ff0b567 Draft: Fix Part_Line offset issue 2021-12-10 02:41:43 +01:00
wmayer 099a8027d6 Part: [skip ci] 0004665: Part/projection tool : Unhandled unknown exception caught when mouse gets over a datum plane 2021-12-10 02:22:11 +01:00
wmayer 9eefd120d1 PD: 0004699: ShapeBinder still touched after recompute 2021-12-10 02:17:07 +01:00
wmayer 12974031a9 PD: 0004582: Mulit-transformation dialog cannot be cancelled 2021-12-10 02:10:20 +01:00
Uwe 2982c875b2 PD: 0004759: Bad error message when creating pad with 0 length
cherry-picked from commit 6167e9f77a
2021-12-09 03:27:34 +01:00
Syres916 6530e36418 Change macro path selection from File to Folder 2021-12-04 21:56:30 +01:00
Yorik van Havre c5eca93a20 Start: Fixed faling test 2021-11-26 03:42:15 +01:00
Heewa Barfchin e2fd673287 Start: fix bug when custom dir missing 2021-11-26 03:39:22 +01:00
Chris Hennes 45e1973680 [Start] Correct TestStart installation location 2021-11-26 03:35:53 +01:00
Yorik van Havre e97f4985c8 Merge pull request #4912 from sprhawk/master
ReverseEngineering: compile with PCL-1.12.0
2021-11-26 02:27:17 +01:00
Bernd Waibel f29d8d8dde [Fem] fix femtest failure with yaml.load
Solves an issue with using an outdated call to yaml.load
as described in
https://forum.freecadweb.org/viewtopic.php?f=10&t=57617

Signed-off-by: Bernd Waibel <waebbl-gentoo@posteo.net>
2021-11-26 02:23:57 +01:00
0penBrain 73ed43d2c1 [Sketcher][Bugfix] Fix crash when applying 'Constrain internal alignment' on contraints, fixes #4790 2021-11-22 20:10:08 +01:00
0penBrain 4bec2964ed [Sheet] Assert non-null pointer before using it 2021-11-22 04:09:12 +01:00
Zheng, Lei be674c362b App: fix crash on copy of Enumeration 2021-11-15 15:21:28 +01:00
Ajinkya Dahale 6ca055d277 [PD] Check if property is named before strcmp 2021-11-13 01:28:17 +01:00
Chris Hennes 3daf116fdf Merge pull request #5149 from donovaly/PD-loft-visibility-fix
[PD] fixes loft visibility on creation and modification
2021-11-08 23:45:52 +01:00
Uwe 951cb89046 [PD] simplify Loft code
- also two automatic style fixes made by MSVC
2021-11-08 23:45:17 +01:00
Ajinkya Dahale b8753a8ede [PartDesign] Fix typo in method name 2021-11-08 23:44:28 +01:00
Uwe 0f1ab68e88 backport commit commit 4f56ee263d
(done this way since cherry-picking etc. failed)
2021-11-07 21:01:49 +01:00
wmayer b33324a5df PD: [skip ci] fix ambiguous shortcut overload in TaskDlgPipeParameters 2021-11-07 18:38:00 +01:00
0penBrain bea3c220ca [Sketcher] Removed lines that was introduced to workaround grid visibility management issues 2021-11-05 03:38:51 +01:00
0penBrain 08880ec7aa [ViewProvider2DObject=>Sketcher] Fix grid visibility management
Error in grid visibility equation that makes grid to disappear when saving document in Edit mode
2021-11-05 03:38:50 +01:00
0penBrain 7ef83f9d4d [ViewProvider2DObject] Fix typo 2021-11-05 03:37:23 +01:00
Chris Hennes 5534bd375a Merge pull request #5098 from realthunder/FixStepColor
Fix STEP import/export color problem
2021-11-05 03:28:50 +01:00
Chris Hennes 765d7f708d Addon manager: Add support for non-master branches 2021-11-04 20:57:45 -05:00
Chris Hennes f069150ef5 Addon manager: correct check for Markdown library 2021-11-04 20:31:35 -05:00
Chris Hennes 68384f549c Addon manager: add support for salsa.debian.org 2021-11-04 20:31:35 -05:00
Uwe af2e83e06b [skip ci] Win installer: prepare for 0.19.3 release 2021-11-04 02:08:21 +01:00
wmayer 999423cd74 Sketcher: [skip ci] handle coincident points when trying to create arc/circle 2021-10-28 17:05:01 +02:00
sliptonic f924551620 Black reformat 2021-10-20 09:34:51 -05:00
sliptonic 27cc2b2a65 Job object doesn't exist in this context.
Derive output name in the output section or default if unknown
2021-10-20 09:34:34 -05:00
Ton 6d334db42c Update PathSanity.py
Output fillename for the report is now the same as the postprocessor job (job.PostProcessorOutputFile), this way the setup file will be autoloaded in LinuxCNC qtDraggon ui and others based on probe-basic.
There is some error checking missing, the check to see if the job.PostProcessorOutputFile is not empty is not there for example. But since the report can only be generated when there is a postprocessor file this is not a big problem.
2021-10-20 09:34:20 -05:00
Chris Hennes 6a441fea8d [Doc] Update URL for Coin3D
Corresponds to commit 67ebeea PR 5103 from @donovaly, adapted for the
0.19 release branch.
2021-10-09 13:21:11 -05:00
Łukasz Stelmach 7622933a16 Arch: Parse window opening modes with more than one digit
Signed-off-by: Łukasz Stelmach <stlman@poczta.fm>
2021-09-30 17:04:52 -05:00
Łukasz Stelmach d292788097 Arch: Fix material color pickers
Provide currently set color as initial value for getColor() to enable
convenient incremental changes.

Do not change the colour if the Cancel buton was pressed.

Signed-off-by: Łukasz Stelmach <stlman@poczta.fm>
2021-09-30 17:04:13 -05:00
Łukasz Stelmach c5d0acce8a Draft: Ensure horizontal orientation of snap_widget
From time to time when switching to other workbenches snap_widget changes
orientation to vertical. Make sure it stays horizontal.

Signed-off-by: Łukasz Stelmach <stlman@poczta.fm>
2021-09-30 17:03:17 -05:00
Russell Johnson b2206d81f3 Path: Downgrade module's debug level to INFO 2021-10-07 13:43:33 -05:00
Russell Johnson ee5b201b1e Path: Fix Face Region boundary shape usage
This commit removes automatic edge extension for `Face Region` boundary shape.  It applies the `Clear Edges` toggle for `Face Region`.  It applies `Exclude Raised Areas` correctly.  The problem of collision paths for `Clear Edges` with `Exclude Raised Areas` for certain use cases remains and is not fixed with this commit.
2021-10-07 13:37:51 -05:00
Russell Johnson 1ecd012a02 Path: Fix relative paths for bit path attributes in library files 2021-10-07 13:37:17 -05:00
Russell Johnson dab2d652ac Path: Fixes #0004647, relative shape file locations
This solution restricts relative shape files to filename only within the toolbit file.
2021-10-07 13:36:49 -05:00
Russell Johnson c8109c9401 Path: Fix readonly lockout bug with blank expression 2021-10-07 13:34:01 -05:00
Russell Johnson 39da720c8a Path: Fix bug with inaccurate Task Panel values upon new op creation
Path: Fix bug with inaccurate Task Panel values upon new op creation
2021-10-07 13:33:12 -05:00
Noah eaf5814778 Path: fix invalid JSON in 45degree_chamfer.fctb tool bit
Fixes an issue reported in https://forum.freecadweb.org/viewtopic.php?f=15&t=54307.

> Error loading tool: 45degree_chamfer.fctb : Expecting property name enclosed in double quotes: line 12 column 3 (char 298)
2021-10-07 13:19:40 -05:00
sliptonic da51b0be53 Update 45degree_chamfer.fctb 2021-10-07 13:19:14 -05:00
Claas Ahlrichs bba3a23405 Update grbl_post.py 2021-10-07 13:10:47 -05:00
ho-ho-ho e6673d60ad Update grbl_post.py
Append new line to return-to line
2021-10-07 13:09:59 -05:00
ho-ho-ho f1e4cb4433 Path: fix grbl --return-to placement 2021-10-07 13:07:36 -05:00
Russell Johnson db2d518aa2 Path: Remove Side assignment to Outside for full model profiles
The profile operation is forcing  cut side to `Outside` when profiling whole models.  This change in code also allows for profiling `Inside` of entire models.  Apart from limiting profiling capabilities of entire models, this override could cause problems with profiling of selected faces or edges in very specific use cases.  Also, this fix removes the property assignment of a key control property within the execution code, which should not happen, apart from feedback properties.
2021-10-07 13:03:03 -05:00
sliptonic 0d3c05447a Path bug splitting gcode by Fixture 2021-10-07 13:02:05 -05:00
sliptonic 9ed2c3570c fix cancel bug 2021-10-07 11:03:05 -05:00
sliptonic abe65e7a75 removed PathUtils import from all post-processors to avoid the deleted proxy error
I removed or commented out code using this import.  In all cases,
the import was used to get descriptive information from the Job
2021-10-07 10:59:26 -05:00
sliptonic 781cb10a7d fix bug adding TC from job dialog.
When adding tool controllers from the job dialog, it will now
try to match the toolbit file with the currently selected library
and add use the toolnumber from there.  If no match is found,
it will autoincrement from the existing tool controllers
in the job
2021-10-07 10:58:41 -05:00
Chris Nisbet 99d6dd7c5b Path: vcarve - Fix depth calculation
Depths were being calculated incorrectly due to MIC distance getting
divided by scaling factor rather than multiplied by it.

The scaling factor is the inverse of the tan of half the cutting tool
angle, so for a 30 degree bit (say), the scaling factor would be
1 / tan(30/2), or 3.7320.

When given an MIC (which is a radius) of 3.175 (say), and cutting to the
same width with a 30 degree bit, the depth should be 3.175 * 3.7320
(11..849), not 3.175 / 3.7320 (0.8509) as it is currently.
2021-10-07 10:58:04 -05:00
Markus Lampert e2173e88f4 Disable stock/model linking by default 2021-10-07 10:57:09 -05:00
Markus Lampert 5cfb3ce018 Fixed race condition in deleting job when cancelling its task panel 2021-10-07 10:56:54 -05:00
Markus Lampert 597b3b6ba0 Fixed aligning path model along an axis. 2021-10-07 10:56:41 -05:00
sliptonic 5007a72eaa [PATH] Fix bug with spindle not restarting
if output is split by operation spindle should restart when next file is loaded
2021-10-07 10:55:20 -05:00
Russell Johnson e2e002ea27 Path: Fix multi-OS path issue.
Not all operating systems use the same path scheme - the slash direction.  The issue fixed with this commit exists in other parts of the Path workbench
2021-10-07 10:45:20 -05:00
troyp76 a8270021ee Operations were being recalculated even if the dirty state was False.
The "isDirty" function was not being called correctly by the accept call back.
2021-10-07 10:17:38 -05:00
Heewa Barfchin 24550b0ccf Path: check for empty before using - fixes #4645
In a few locations, python objects are used without checking if they
exist and are non-null, which throws missing attribute exceptions. The
fix is to simply check first.
2021-10-07 10:16:47 -05:00
Russell Johnson c9ab285c61 Path: Fix connected multi-face clearing bug
Identified by MLampert.  If multiple faces are selected at varying Z-heights, the `combineConnectedShapes()` method fails to connect them due to offset Z-heights.  This fix places all input faces for that method into the same working plane.
2021-10-07 10:13:59 -05:00
mwganson 31b8344d73 [Spreadsheet] Prevent infinite loop when copy/paste of non-rectangular selection 2021-10-04 17:47:42 -05:00
0penBrain 0f303a785b [Sketcher] Fix 'Reference' checkbox not working for diameter 2021-10-04 20:21:20 +02:00
0penBrain 51ea0ed9e6 [Sketcher] Fix 'Reference' checkbox not working for radius/diameter ; fixes #4627
As a consequence :
Remove message box when several arcs/circles are selected ...
... and enforce creation of equality constraints in this case
Former existing option of adding a dimensional constraint ...
... to each circle encouraged improper constraining
2021-10-04 20:20:52 +02:00
Bernd Hahnebach 9989a2ef4a Test: fix failing doc tests, from commit 20c4c369b3 2021-10-02 08:03:02 +02:00
Bernd Hahnebach 2b9894f3a9 FEM: material task panel, raise max possible young's modul value 2021-10-01 22:18:23 +02:00
wmayer 76c7f52543 Part: [skip ci] workaround for OCCT 7.5.2 2021-10-01 22:07:57 +02:00
Bernd Hahnebach de7cba4669 gitlab CI: fix build 2021-10-01 18:15:17 +02:00
Przemo Firszt 1f024523e6 [UnitTest] Fix UnitTests - use utf-8
On some systems there is a problem with utf-8 during testing. This
commit is trying to address it. Tested only on ubuntu 20.04

Signed-off-by: Przemo Firszt <przemo@firszt.eu>
2021-10-01 17:52:35 +02:00
Przemo Firszt 6989306097 [UnitTest] Replace deg symbol with deg
unittest cannot handle the symbol on some systems. deg is a safe
solution.

Signed-off-by: Przemo Firszt <przemo@firszt.eu>
2021-10-01 17:52:35 +02:00
Bernd Hahnebach 211d74f4a6 CI gitlab: update readme 2021-10-01 17:52:35 +02:00
Przemo Firszt eafe6b73ec [gitlab-ci] gitlab CI on docker initial commit 2021-10-01 17:52:35 +02:00
donovaly 1eb65aa002 [Part] uniform feature sorting
at the moment the sorting is confusing, the sorting in the menu differs from the toolbars and some features even belong in the menu to another category than in the toolbars and one feature has not yet a toolbar entry

This PR implements a uniform sorting for the menu and toolbar and adds the missing toolbar icon
2021-09-29 10:44:43 -05:00
Syres916 969c1eee2d Changes as per @Chennes advice 2021-09-23 12:07:37 -05:00
Syres916 c974f914db [Gui] Preferences - Selection Fix Bug for new...
... users who save an unrelated Preference such as Stylesheet from loosing the default selection settings.
See discussion : https://forum.freecadweb.org/viewtopic.php?f=3&t=58215
2021-09-23 12:07:27 -05:00
Tomas Pavlicek 5a7a2d2f81 TechDraw - Undo for Cosmetics Vertices and Lines 2021-09-23 12:07:08 -05:00
Heewa Barfchin 312d8299cb App: Abort save when unable to finish
In these two cases, the project's file will not contain the latest
changes, so returning as if the save is complete is incorrect and can
lead to data loss (such as on app quit).
2021-09-23 12:06:47 -05:00
Heewa Barfchin 257d22e1e0 Fix app quitting after failed save. Fixes #4098
Return `false` from Document::save() to properly communicate the
failure, which the app-quit process already handles by aborting.
2021-09-23 12:06:32 -05:00
Syres916 a43995fc45 [AddonManager] stderr remove translate 2021-09-23 12:06:08 -05:00
Syres916 0988177e62 [AddonManager] Handle stderr from git status
See discussion https://forum.freecadweb.org/viewtopic.php?f=10&t=62265
2021-09-23 12:05:59 -05:00
turn211 7b5e18a075 Gui: ProDark Stylesheet QT Icon Fix
forum thread: https://forum.freecadweb.org/viewtopic.php?f=34&t=57427
2021-04-15 11:17:08 +02:00
turn211 ed87d3aceb [Stylesheet] ProDark: major bugfix for add-ons
https://forum.freecadweb.org/viewtopic.php?f=34&t=55134&start=100
2021-04-15 11:15:49 +02:00
turn211 133ef7173d Gui: Update usability enhancements to ProDark theme
forum thread: https://forum.freecadweb.org/viewtopic.php?f=34&t=55134
2021-04-15 11:15:33 +02:00
donovaly 8e7a8b1e7b [FEM] fix specific heat of air
- also adjust values slightly according to various sources

Since a factor 1000 is a big mistake and air is the most common gas, please commit this also for FC 0.19
2021-04-14 14:06:58 +02:00
Chris Hennes b3abe32683 [Draft] Eliminate required GUI for importDXF 2021-04-14 13:59:36 +02:00
Chris Hennes 53b4eb0b2e [Start] Correct TestStart installation location 2021-04-14 13:57:42 +02:00
Chris Hennes 51855e5341 [GUI] Stylesheet fix for icons in Qt file dialog
Work by @turn211.
2021-04-14 13:34:28 +02:00
wmayer 12055a22d8 Py: fix memory leak 2021-04-14 13:24:32 +02:00
Chris Hennes 6f67fbc425 [GUI] Remove explicit triangle styling from tabs
On Windows the lower tabs of the PropertyView were being set to
triangular, which breaks stylesheets. This removes that code, so they
now take on whatever the standard shape is on the system.

Fixes #0004599
2021-04-04 09:58:35 +02:00
Matthijs Kooijman 83e308c8eb Gui: Enable compression of tablet motion events
By default (on platforms that support it, X11 and Windows currently) 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, which is what FreeCAD uses) are not compressed by default (to
allow maximum precision when e.g. hand-drawing curves), leading to
unacceptable slowdowns using a tablet pen.

This commit enable compression for tablet events here to solve that and
make use of a tablet just as smooth as a mouse with FreeCAD.

This can (and likely will) lead to some movement events being dropped,
but since there is no freeform curve drawing tool, that should not be
problematic (and if it is ever added, it could still work without
compression if the mouse movement event handler is written to be fast
enough).
2021-03-29 14:10:56 +02:00
donovaly de1d0acaea [installer] improve uninstalling
- fix missing removal of the *.FCStd extension for local users
- FC-specific file extensions might appear in the Windows registry. The aim of the uninstaller is to leave a clear registry without traces of FC.
2021-03-28 16:44:20 +02:00
wmayer e239684102 TD: fixes #0004598: Segfault when deleting template without page 2021-03-28 13:40:35 +02:00
tomate44 aedd1f96e4 PartDesign Helix: update NbTurns in Pitch-Height-Angle mode 2021-03-28 13:17:09 +02:00
lvk88 e7c796edb4 [GUI] Enable dragging in dependency graph view
This commit makes it possible to drag the dependency graph using the
left mouse button.

See issue #3896.
2021-03-28 12:10:43 +02:00
wmayer 6858586642 Import: [skip ci] avoid conflicting class names in global namespace 2021-03-19 15:18:57 +01:00
wmayer a88db11e0a Fem: [skip ci] set backend of matplotlib to Qt5Agg 2021-03-11 20:48:53 +01:00
donovaly f4574cf02d [Gui] fix HiDPI rounding bug
As reported in https://forum.freecadweb.org/viewtopic.php?f=10&t=56425&start=20#p485809
this PR fixes the problem reported here: https://forum.freecadweb.org/viewtopic.php?f=10&t=56425&start=20#p485759
2021-03-10 15:23:33 +01:00
Chris Hennes 159a71bba7 [0.19][Web] Remove HiDPI fix when using QTWEBVIEW
The screen scale adjustment code here should not be necessary when using
the Chromium-based QtWebView widget, which correctly handles logical vs.
device px units. The scaling causes poor font size choice when used on
ultrawide monitors, as reported in
https://forum.freecadweb.org/viewtopic.php?p=485431
2021-03-08 18:51:06 +01:00
donovaly dfc3e2b9a6 [Main] set Coin environment variable
as discussed in https://forum.freecadweb.org/viewtopic.php?f=10&t=56386&start=10 we need to set this environment variable for Coin on Windows
2021-03-08 15:21:17 +01:00
donovaly 27b568e4e4 update for FC 0.19.0 2021-03-05 12:24:05 +01:00
wmayer a266852510 PD: AddressSanitizer: heap-use-after-free
Fix crash inside TaskDlgSketchBasedParameters::reject()
2021-03-03 15:53:44 +01:00
donovaly 408128838c [PD] fix multi-transform View
- fixes bug 4581
  See the first issue reported here:
  https://forum.freecadweb.org/viewtopic.php?f=3&t=56093#p482553

- also fix issue that one could set 1 occurrence for polar patterns despite 2 are required at least

- also fix potential dereferencing null pointer (reported by MSVC)
2021-03-02 10:40:13 +01:00
Yorik van Havre fc0c1069d2 Arch: Fixed SectionPlane outside objects bug in ArchSectionPlane - Fixes #4549 2021-03-01 16:50:10 +01:00
wmayer 5ea583466d Gui: [skip ci] allow to unbind() an ExpressionBinding and automatically unbind it if the observed object has been deleted
For more details see: https://forum.freecadweb.org/viewtopic.php?f=8&t=56097
2021-03-01 16:00:08 +01:00
152 changed files with 2100 additions and 1418 deletions
+43
View File
@@ -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
View File
@@ -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
+4 -5
View File
@@ -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) {
+1
View File
@@ -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());
+1 -1
View File
@@ -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);
}
+1 -1
View File
@@ -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>
+17
View File
@@ -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");
+8 -5
View File
@@ -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;
+3
View File
@@ -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>
+4 -4
View File
@@ -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"));
}
+1
View File
@@ -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;
}
+20 -1
View File
@@ -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();
}
}
+7 -4
View File
@@ -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;
};
+89 -1
View File
@@ -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();
+2
View File
@@ -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()");
}
}
-3
View File
@@ -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();
+2 -2
View File
@@ -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;
+12
View File
@@ -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
+12
View File
@@ -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
+12
View File
@@ -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
+11
View File
@@ -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
+12
View File
@@ -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
+12
View File
@@ -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
+12
View File
@@ -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
+12
View File
@@ -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
+12
View File
@@ -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
+12
View File
@@ -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
+12
View File
@@ -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
View File
@@ -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 */
+23
View File
@@ -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();
+6
View File
@@ -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;
+1 -1
View File
@@ -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 ) {
+4
View File
@@ -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_;
+12 -10
View File
@@ -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
+37 -11
View File
@@ -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:
+11 -9
View File
@@ -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"
+7 -5
View File
@@ -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)
+3
View File
@@ -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.
+9 -2
View File
@@ -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))
+5 -5
View File
@@ -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
1 # Data structure:
658 Eurocode timber,47x300,R,47,300
659 Eurocode timber,63x150,R,63,150
660 Eurocode timber,63x175,R,63,175
661 Eurocode timber,63x200,R,63,200
662 Eurocode timber,63x225,R,63,225
663 Eurocode timber,75x100,R,75,100
664 Eurocode timber,75x150,R,75,150
665 Eurocode timber,75x175,R,75,175
666 Eurocode timber,75x200,R,75,200
667 Eurocode timber,75x225,R,75,225
668 Eurocode timber,75x250,R,75,250
669 Eurocode timber,75x300,R,75,300
679 # Rectangular Hollow Section (RHS) profiles
680 # Category,Name,RH,width,height,thickness
681 RHS,RHS50x30,RH,50,30,2.9
682 RHS,RHS50x30,RH,50,30,3.0
683 RHS,RHS50x30,RH,50,30,3.2
684 RHS,RHS50x30,RH,50,30,3.6
685 RHS,RHS50x30,RH,50,30,4.0
+4 -1
View File
@@ -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);
+5 -5
View File
@@ -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)
+2
View File
@@ -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()
+2 -4
View File
@@ -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()
+1
View File
@@ -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"),
+1
View File
@@ -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"),
+1
View File
@@ -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)
+8 -6
View File
@@ -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()
+28 -21
View File
@@ -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
+8 -11
View File
@@ -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
+8 -2
View File
@@ -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
+6 -20
View File
@@ -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)
+1 -1
View File
@@ -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>
+1 -1
View File
@@ -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
+2 -1
View File
@@ -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:
+18 -23
View File
@@ -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);
}
}
+4 -1
View File
@@ -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);
+24 -15
View File
@@ -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)) {
+2 -2
View File
@@ -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;
};
+59 -25
View File
@@ -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);
+7 -1
View File
@@ -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;
}
+4 -3
View File
@@ -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:
+4 -4
View File
@@ -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"
+1
View File
@@ -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;
+7 -6
View File
@@ -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!");
+3 -1
View File
@@ -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) {
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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);
+3 -3
View File
@@ -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
+9 -13
View File
@@ -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) {
-3
View File
@@ -46,9 +46,6 @@ protected:
bool setEdit(int ModNum);
void unsetEdit(int ModNum);
private:
void startDefaultEditMode();
private:
ViewProviderAttachExtension extension;
};
+7 -6
View File
@@ -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");
+1
View File
@@ -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())
+5 -5
View File
@@ -791,9 +791,9 @@ void Hole::updateHoleCutParams()
}
}
// handle legacy types but dont change user settings for
// handle legacy types but don't change user settings for
// user defined None, Counterbore and Countersink
// handle legacy types but dont 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";
}
}
}
+14 -3
View File
@@ -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
+13 -11
View File
@@ -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);
}
+3 -3
View File
@@ -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();
};
+1 -1
View File
@@ -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();
+13 -5
View File
@@ -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
+15 -3
View File
@@ -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
+61 -36
View File
@@ -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):
+2 -1
View File
@@ -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:
+84 -62
View File
@@ -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()
+9 -5
View File
@@ -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 ...")
+12 -1
View File
@@ -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