Skip to content

Commit eba13b4

Browse files
committed
Python Workbench Template with a demo feature
1 parent 5ce75d4 commit eba13b4

File tree

7 files changed

+694
-0
lines changed

7 files changed

+694
-0
lines changed

Feature1.py

+130
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# -*- coding: utf-8 -*-
2+
3+
__title__ = "Feature1"
4+
__author__ = "Christian Bergmann"
5+
__license__ = "LGPL 2.1"
6+
__doc__ = "An example for a workbench feature"
7+
8+
import PythonWorkbenchTemplate
9+
import os
10+
import FreeCADGui
11+
import FreeCAD
12+
from FreeCAD import Vector
13+
import Part
14+
15+
16+
class Feature1Worker:
17+
def __init__(self,
18+
fp, # an instance of Part::FeaturePython
19+
base = None,
20+
green = False):
21+
fp.addProperty("App::PropertyLink", "Base", "Feature1", "This object will be modified by this feature").Base = base
22+
fp.addProperty("App::PropertyBool", "Green", "Feature1", "Colorize the feature green").Green = green
23+
24+
fp.Proxy = self
25+
26+
def execute(self, fp):
27+
'''Do something when doing a recomputation, this method is mandatory'''
28+
redrawFeature1(fp)
29+
30+
def onChanged(self, fp, prop):
31+
'''Do something when a property has changed'''
32+
if prop == "Base":
33+
redrawFeature1(fp)
34+
35+
if prop == "Green":
36+
changeFeature1Color(fp)
37+
38+
39+
class Feature1ViewProvider:
40+
def __init__(self, vobj):
41+
'''Set this object to the proxy object of the actual view provider'''
42+
vobj.Proxy = self
43+
self.Object = vobj.Object
44+
45+
def getIcon(self):
46+
'''Return the icon which will appear in the tree view. This method is optional and if not defined a default icon is shown.'''
47+
return (os.path.join(PythonWorkbenchTemplate.get_module_path(), "Resources", "icons", "feature1.svg"))
48+
49+
def attach(self, vobj):
50+
'''Setup the scene sub-graph of the view provider, this method is mandatory'''
51+
self.Object = vobj.Object
52+
self.onChanged(vobj, "Base")
53+
54+
def updateData(self, fp, prop):
55+
'''If a property of the handled feature has changed we have the chance to handle this here'''
56+
pass
57+
58+
def claimChildren(self):
59+
'''Return a list of objects that will be modified by this feature'''
60+
return [self.Object.Base]
61+
62+
def onDelete(self, feature, subelements):
63+
'''Here we can do something when the feature will be deleted'''
64+
return True
65+
66+
def onChanged(self, fp, prop):
67+
'''Here we can do something when a single property got changed'''
68+
pass
69+
70+
def __getstate__(self):
71+
'''When saving the document this object gets stored using Python's json module.\
72+
Since we have some un-serializable parts here -- the Coin stuff -- we must define this method\
73+
to return a tuple of all serializable objects or None.'''
74+
return None
75+
76+
def __setstate__(self,state):
77+
'''When restoring the serialized object from document we have the chance to set some internals here.\
78+
Since no data were serialized nothing needs to be done here.'''
79+
return None
80+
81+
82+
def redrawFeature1(fp):
83+
# check plausibility of all parameters
84+
if not fp.Base:
85+
return
86+
87+
# fp.Shape contains the newly created object
88+
fp.Shape = fp.Base.Shape.copy()
89+
changeFeature1Color(fp)
90+
91+
92+
def changeFeature1Color(fp):
93+
if fp.Green:
94+
fp.ViewObject.ShapeColor = (0.00, 1.00, 0.00)
95+
else:
96+
fp.ViewObject.ShapeColor = (1.00, 0.00, 0.00)
97+
98+
99+
class Feature1():
100+
'''This class will be loaded when the workbench is activated in FreeCAD. You must restart FreeCAD to apply changes in this class'''
101+
102+
def Activated(self):
103+
'''Will be called when the feature is executed.'''
104+
# Generate commands in the FreeCAD python console to create Feature1
105+
FreeCADGui.doCommand("import PythonWorkbenchTemplate")
106+
107+
selection = FreeCADGui.Selection.getSelectionEx()
108+
if len(selection) > 0:
109+
FreeCADGui.doCommand("base = FreeCAD.ActiveDocument.getObject('%s')"%(selection[0].ObjectName))
110+
FreeCADGui.doCommand("PythonWorkbenchTemplate.makeFeature1(base)")
111+
else:
112+
FreeCADGui.doCommand("PythonWorkbenchTemplate.makeFeature1()")
113+
114+
115+
def IsActive(self):
116+
"""Here you can define if the command must be active or not (greyed) if certain conditions
117+
are met or not. This function is optional."""
118+
if FreeCAD.ActiveDocument:
119+
return(True)
120+
else:
121+
return(False)
122+
123+
def GetResources(self):
124+
'''Return the icon which will appear in the tree view. This method is optional and if not defined a default icon is shown.'''
125+
return {'Pixmap' : os.path.join(PythonWorkbenchTemplate.get_module_path(), "Resources", "icons", "feature1.svg"),
126+
'Accel' : "", # a default shortcut (optional)
127+
'MenuText': "Feature1",
128+
'ToolTip' : "A template for a workbench feature" }
129+
130+
FreeCADGui.addCommand('Feature1', Feature1())

Init.py

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# FreeCAD init script of the PythonWorkbenchTemplate module
2+
# (c) 2020 Christian Bergmann LGPL

InitGui.py

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# -*- coding: utf-8 -*-
2+
3+
__title__ = "FreeCAD Default Workbench - Init file"
4+
__author__ = "Christian Bergmann"
5+
__url__ = ["http://www.freecadweb.org"]
6+
__version__ = "0.0.1"
7+
8+
9+
class PythonWorkbenchTemplate (Workbench):
10+
def __init__(self):
11+
import os
12+
import PythonWorkbenchTemplate
13+
self.__class__.MenuText = "PythonWorkbenchTemplate"
14+
self.__class__.ToolTip = "A template for a new workbench"
15+
self.__class__.Icon = os.path.join(PythonWorkbenchTemplate.get_module_path(), "Resources", "icons", "freecad.svg")
16+
17+
def Initialize(self):
18+
"This function is executed when FreeCAD starts"
19+
# import here all the needed files that create your FreeCAD commands
20+
import Feature1
21+
22+
self.list = ["Feature1"] # A list of command names created in the line above
23+
self.appendToolbar("Curved Shapes", self.list) # creates a new toolbar with your commands
24+
self.appendMenu("Curved Shapes", self.list) # creates a new menu
25+
26+
def Activated(self):
27+
"This function is executed when the workbench is activated"
28+
return
29+
30+
def Deactivated(self):
31+
"This function is executed when the workbench is deactivated"
32+
return
33+
34+
def ContextMenu(self, recipient):
35+
"This is executed whenever the user right-clicks on screen"
36+
# "recipient" will be either "view" or "tree"
37+
self.appendContextMenu("Curved Shapes", self.list) # add commands to the context menu
38+
39+
def GetClassName(self):
40+
# this function is mandatory if this is a full python workbench
41+
return "Gui::PythonWorkbench"
42+
43+
Gui.addWorkbench(PythonWorkbenchTemplate())

PythonWorkbenchTemplate.py

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import os
2+
import FreeCAD
3+
from importlib import reload
4+
5+
def get_module_path():
6+
""" Returns the current module path.
7+
Determines where this file is running from, so works regardless of whether
8+
the module is installed in the app's module directory or the user's app data folder.
9+
(The second overrides the first.)
10+
"""
11+
return os.path.dirname(__file__)
12+
13+
14+
def makeFeature1(base = None, green = False):
15+
'''Python command to create a Feature1'''
16+
import Feature1
17+
reload(Feature1) # causes FreeCAD to reload Feature1.py every time a new Feature1 is created.
18+
fp = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Feature1")
19+
Feature1.Feature1Worker(fp, base, green)
20+
Feature1.Feature1ViewProvider(fp.ViewObject)
21+
FreeCAD.ActiveDocument.recompute()
22+
return fp
23+

README.md

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Python Workbench Template
2+
3+
A template for creating a new FreeCAD workbench in Python.
4+
FreeCAD offers great opportunities to create scripted objects. This should be a starting point to create your own workbench.
5+
6+
## Installation
7+
8+
### Automatic Installation
9+
**Note: This is the recommended way to install this workbench.**
10+
The Python Workbench Template will be available soon through the builtin FreeCAD [Addon Manager](https://github.com/FreeCAD/FreeCAD-addons#1-builtin-addon-manager).
11+
Once installed all that is needed is to restart FreeCAD and the workbench will be available in the [workbench dropdown list](https://freecadweb.org/wiki/Std_Workbench) menu.
12+
13+
### Manual Installation
14+
15+
```bash
16+
cd ~/FreeCAD/Mod/
17+
git clone https://github.com/chbergmann/PythonWorkbenchTemplate.git
18+
```
19+
When you restart FreeCAD, "Python Workbench Template" workbench should now show up in the [workbench dropdown list](https://freecadweb.org/wiki/Std_Workbench).
20+
21+
## Getting started with a new FreeCAD workbench
22+
- Create a new git repository and copy the contents of this project to your new project
23+
- Rename PythonWorkbenchTemplate.py to YourWorkbenchsName.py. Search all files for PythonWorkbenchTemplate and replace with the name of your workbench
24+
- Rename Feature1.py with YourNewFeature.py
25+
- Edit InitGui.py. Delete Feature1 and add your new feature instead. Edit the \__title\__, \__author\__, \__url\__ and \__version\__ tags.
26+
- Write your new feature and test it well.
27+
- Write a documentation in README.md. Explain the purpose of your workbench. Explain your features. Screenshots are great.
28+
- Announce your workbench in the [FreeCAD forum](https://forum.freecadweb.org/index.php). Add the link of your new thread in README.md
29+
- Add your workbench to the [Addon manager](https://github.com/FreeCAD/FreeCAD-addons)
30+
31+
## Tools
32+
### ![Feature1Icon](./Resources/icons/feature1.svg) Feature1
33+
Colorizes a selected object red or green. For demonstration how to write a workbench feature.
34+
35+
#### Parameters
36+
- Base: The object to colorize
37+
- Green: if True, the linked object will be colored green, otherwise red.
38+
39+
40+
## Discussion
41+
Please offer feedback or connect with the developer via the [dedicated FreeCAD forum thread](LINK).
42+
43+
## License
44+
GNU Lesser General Public License v3.0

0 commit comments

Comments
 (0)