You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: technical/CreatePythonBindingForCpp.md
+17-15Lines changed: 17 additions & 15 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,4 +1,10 @@
1
-
# Background
1
+
---
2
+
layout: default
3
+
---
4
+
5
+
# Create a Python Binding for C++
6
+
7
+
## Background
2
8
3
9
It becomes necessary at times to expand the FreeCAD API further by exposing functions that are available in the source code in c++ to the python. This process is generally referred to as creating a binding.
4
10
@@ -18,7 +24,7 @@ The XML file YourClassPy.xml provides information about the functions and attrib
18
24
19
25
For this example, we will look at the wrapper for the Base::Axis C++ class. The XML description file begins with:
@@ -42,7 +48,7 @@ For this example, we will look at the wrapper for the Base::Axis C++ class. The
42
48
43
49
Following this preamble, a list of methods and attributes is given. The format of a method is:
44
50
45
-
```XML
51
+
```xml
46
52
<Methode Name##"move">
47
53
<Documentation>
48
54
<UserDocu>
@@ -55,7 +61,7 @@ Following this preamble, a list of methods and attributes is given. The format o
55
61
56
62
The format of an attribute is:
57
63
58
-
```XML
64
+
```xml
59
65
<Attribute Name##"Direction" ReadOnly##"false">
60
66
<Documentation>
61
67
<UserDocu>Direction vector of the Axis</UserDocu>
@@ -66,24 +72,25 @@ The format of an attribute is:
66
72
67
73
For an attribute, if "ReadOnly" is false, you will provide both a getter and a setter function. If it is true, only a getter is allowed. In this case we will be required to provide two functions in the implementation C++ file:
68
74
69
-
```C++
75
+
```cpp
70
76
Py::Object AxisPy::getDirection(void) const
77
+
````
71
78
72
79
and:
73
80
81
+
```cpp
74
82
void AxisPy::setDirection(Py::Object arg)
75
83
```
76
84
85
+
## Implementation C++ File
77
86
78
-
## Implementation Cplusplus File
79
-
80
-
The implementation C++ file YourClassPyImp.cpp provides the "glue" that connects the C++ and Python structures together, effectively translating from one language to the other. The FreeCAD C++-to-Python system provides a number of C++ classes that map to their corresponding Python type. The most fundamental of these is the incode|Py::Object class -- rarely created directly, this class provides the base of the inheritance tree, and is used as the return type for any function that is returning Python data.
87
+
The implementation C++ file `YourClassPyImp.cpp` provides the "glue" that connects the C++ and Python structures together, effectively translating from one language to the other. The FreeCAD C++-to-Python system provides a number of C++ classes that map to their corresponding Python type. The most fundamental of these is the incode `Py::Object` class - rarely created directly, this class provides the base of the inheritance tree, and is used as the return type for any function that is returning Python data.
81
88
82
89
### Include Files
83
90
84
91
Your C++ implementation file will include the following files:
85
92
86
-
```C++
93
+
```cpp
87
94
#include "PreCompiled.h"
88
95
89
96
#include "YourClass.h"
@@ -99,7 +106,7 @@ Of course, you may include whatever other C++ headers your code requires to func
99
106
100
107
Your C++ implementation must contain the definition of the PyInit function: for example, for the Axis class wrapper, this is
101
108
102
-
```C++
109
+
```cpp
103
110
int AxisPy::PyInit(PyObject* args, PyObject* /*kwd*/)
104
111
105
112
//Within this function you will most likely need to parse incoming arguments to the constructor: the most important function for this purpose is the Python-provided incode|PyArg_ParseTuple. It takes in the
@@ -123,7 +130,6 @@ For a complete list of format specifiers see [https://docs.python.org/3/c-api/ar
The basic structure of a program to expose functionality to Python is something like this:
@@ -147,14 +153,10 @@ There is a convention for return values from our C++/Python connections:
147
153
* xxxxxPyImp routines return a PyObject* pointer (see TopoShapePyImp.cpp)
148
154
* AppmyModulePy.cpp routines return a Py::Object (see https://github.com/FreeCAD/FreeCAD/blob/master/src/Mod/Part/App/AppPartPy.cpp and FreeCAD/src/Mod/Part/AppPartPy.cpp.
Copy file name to clipboardExpand all lines: technical/TheApplicationModule.md
+4-5Lines changed: 4 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,15 +1,14 @@
1
1
---
2
2
layout: default
3
-
mermaid: true
4
3
---
5
4
6
-
# "The Application Module"
5
+
# The Application Module
7
6
8
-
"An overview of application module structure."
7
+
An overview of application module structure.
9
8
10
-
The functionality of FreeCAD is separated into Modules. Some Modules are built into FreeCAD and some are Extension Modules (a form of plug-in). Once installed, Extension Modules behave exactly as built-in Modules.
9
+
The functionality of FreeCAD is separated into Modules. Some Modules are built into FreeCAD and some are Extension Modules (a form of plug-in). Once installed, Extension Modules behave exactly as built-in Modules.
11
10
12
-
Application Modules provide specialized functions and may store specialized data. Examples of Application Modules are Arch (for buildings) and Sketcher (for drawing Sketches).
11
+
Application Modules provide specialized functions and may store specialized data. Examples of Application Modules are Arch (for buildings) and Sketcher (for drawing Sketches).
13
12
14
13
Application Modules are almost always divided into two parts: App which manages the relevant document objects and operations on them, and Gui which handles the display.
Copy file name to clipboardExpand all lines: technical/developerglossary.md
+3-6Lines changed: 3 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,12 +1,12 @@
1
1
---
2
2
layout: default
3
3
---
4
-
# "Developer's Glossary"
5
4
6
-
"Some terms that a developer may run across."
5
+
# Developer's Glossary
7
6
8
-
Note that there may be subtle differences in how some terms are used by deveopers vs how they are used by users.
7
+
Some terms that a developer may run across.
9
8
9
+
Note that there may be subtle differences in how some terms are used by deveopers vs how they are used by users.
10
10
11
11
* Binding: the mechanism for linking C++ functionality to and from Python.
12
12
* CI (Continuous Integration): the mechanism by which Pull Requests are automatically built and unit tested.
@@ -17,9 +17,6 @@ Note that there may be subtle differences in how some terms are used by deveoper
17
17
* Pull Request: how a contributor indicates that they have a change to be merged
18
18
* ViewProvider: an object that provides painting services for a Feature. The ViewProvider is notified of changes in a Features properties and, if the change affects the visual representation of the Feature, updates the display. Note that in some modules (ex TechDraw with the Qt GraphicsFramework) there is another layer of functionality that manages the painting.
19
19
20
-
21
-
22
-
23
20
## See Also
24
21
25
22
*[FreeCAD glossary wiki entry](https://wiki.freecad.org/Glossary)
@@ -19,8 +20,8 @@ Technical information of interest to Contributors.
19
20
-[Coin3d](https://www.coin3d.org/): a [scenegraph](https://wiki.freecad.org/Scenegraph) manager based on OpenInventor that handles drawing in the 3d window.
20
21
-[Pivy](https://wiki.freecad.org/Pivy): a Python binding for Coin3d
21
22
22
-
23
23
## Modifying FreeCAD
24
+
24
25
- Contributing to FreeCAD
25
26
- The process for submitting changes to FreeCAD is described in the [CONTRIBUTING.md](https://github.com/FreeCAD/FreeCAD/blob/master/CONTRIBUTING.md)
26
27
file in the root of the source tree.
@@ -30,11 +31,8 @@ Technical information of interest to Contributors.
30
31
-[Create a Python Binding for C++ Class](./CreatePythonBindingForCpp.md)
31
32
-[Checklist for Adding a Feature to a Workbench in C++](./ChecklistForNewFeatureC++.md)
How to write code with strings that should be translated
7
+
How to write code with strings that should be translated.
7
8
8
9
In most cases, any user-visible text in FreeCAD should be made translatable. Exceptions to this general rule are:
9
10
1. Text that only appears as log-level messages in the Report View
@@ -16,20 +17,22 @@ Some general guidelines when constructing strings for translation:
16
17
* The NOOP-versions of the Qt translation functions extract the string for translation purposes, but *do not* replace the string in place with its translated equivalent. They should generally only be used in classes derived from Gui::Command for things like the menu entry and tooltip. The Command class handles actually loading the translated string.
17
18
* In a non-QObject-derived class, use `Q_DECLARE_TR_FUNCTIONS(MyClass)` to give your class access to the `tr()` function. See also [the Qt documentation](https://doc.qt.io/qt-5/i18n-source-translation.html).
18
19
19
-
# Qt Translation Functions
20
+
##Qt Translation Functions
20
21
21
-
## C++
22
+
###C++
22
23
23
24
The main translation function for C++ code is `tr()`, automatically defined in any class derived from `QObject`. It automatically sets the "context" of the translation to the name of the class, providing disambiguation between the same string in different parts of FreeCAD, where the meaning might be different. It generates a `QString` out of a string literal:
24
-
```
25
+
26
+
```cpp
25
27
voidSpecialWidget::DoThings()
26
28
{
27
29
this->labelThing.setText(tr("This will get translated")); // Context is "SpecialWidget"
28
30
}
29
31
```
30
32
31
33
If your class is not derived from `QObject`, include the Q_DECLARE_TR_FUNCTIONS macro when defining your class to gain the `tr()` function:
32
-
```
34
+
35
+
```cpp
33
36
#include<QCoreApplication>
34
37
35
38
classNotAWidget
@@ -44,33 +47,42 @@ public:
44
47
Technically `tr()` can take an additional string: a "comment" that is displayed to translators, but is not itself translated. This is rarely used.
45
48
46
49
To do string replacement use `QString::arg()`, for example:
47
-
```
50
+
51
+
```cpp
48
52
label.setText(tr("Item %1 of %2 confabulated. Please wait...").arg(i).arg(total));
49
53
```
54
+
50
55
The string "Item %1 of %2 confabulated. Please wait..." will be presented to translators, but CrowdIn will prevent them from removing the placeholders accidentally.
51
56
52
57
Note that in many places in the FreeCAD source code you will see uses of `QT_TR_NOOP` - this is *only* used in cases where the string is later passed through a separate call to `tr()`. If you aren't sure, check with a Maintainer, and when in doubt, `tr()` is probably what you need.
53
58
54
-
## Python
59
+
###Python
55
60
56
61
In your Python code, import FreeCAD, then create a function called `translate` with the following code:
57
-
```
62
+
63
+
```python
58
64
translate = FreeCAD.Qt.translate
59
65
```
66
+
60
67
It then gets used similarly to `tr()` in C++, but with a manually-specified context:
61
-
```
68
+
69
+
```python
62
70
print(translate("MyMod", "This will get translated"))
63
71
```
72
+
64
73
Note that "translate" is not a true function: it is really a tag that the lupdate utility uses to identify strings for translation. You *cannot* rename it, or use it with non-literal strings, etc. You also cannot use f-strings, or Python string concatenation:
print(translate("MyMod", "This"" also ""won't work")) # NO!
69
79
```
70
80
To do argument replacement use the `format` function of Python's string class:
71
-
```
81
+
82
+
```python
72
83
print(translate("MyMod", "There are {} widgets present, out of {} total").format(present, total))
73
84
```
85
+
74
86
(Note that the string sent to translators is "There are {} widgets present, out of {} total" -- the format function is called on the string that is *returned* from the translate function).
75
87
76
88
## UI Files
@@ -79,17 +91,21 @@ For the most part, all strings in UI files are automatically subject to translat
79
91
80
92
## Translating plurals
81
93
82
-
Many languages have complex pluralization rules. To support this, you can write strings that are designed for pluralization, including in English, by specifying a parameter that indicates how many of a thing there are. The translation system will dynamically select the correct translation (assuming translators wrote one), even for English. For example
83
-
```
94
+
Many languages have complex pluralization rules. To support this, you can write strings that are designed for pluralization, including in English, by specifying a parameter that indicates how many of a thing there are. The translation system will dynamically select the correct translation (assuming translators wrote one), even for English. For example:
95
+
96
+
```cpp
84
97
int nErrors = getNumberOfErrors(); // Might be zero, might be one, might be some other number.
85
98
tr("There were %n errors.", "", nErrors);
86
99
```
100
+
87
101
Translators will be given the opportunity to translate this string in several variants (depending on the language they are translating for). For example, in English we would have:
88
-
```
102
+
103
+
```txt
89
104
There were 0 errors.
90
105
There was 1 error.
91
106
There were 2 errors.
92
107
```
108
+
93
109
In other languages there might be more than two variants, the sentence structure might change completely, etc. Qt and the CrowdIn translation platform support this structure.
94
110
95
111
## Testing your strings
@@ -99,29 +115,35 @@ The translation process has several steps, each of which you can examine during
99
115
### String extraction
100
116
101
117
To determine whether your strings are being correctly extracted, you can directly run the `lupdate` command on the file you are working on, using a dummy TS output file. `lupdate` is included in your Qt installation (note that internally we use lupdate from Qt 6.4 -- this is particularly important if you are testing Python code, as several major problems were address by a patch we submitted to Qt 6.4).
102
-
```
118
+
119
+
```bash
103
120
lupdate MySourceCodeFile.cpp --ts test.ts
104
121
```
122
+
105
123
will generate the file test.ts -- you can examine it to ensure your string appears with the expected context in that file. In particular, make sure that each string makes sense alone: otherwise, without context, translators will not know what they should replace it with.
106
124
107
125
### String replacement
108
126
109
127
To determine whether the string is being replaced correctly, you can create a dummy language file from the above test.ts file, and inject it into your FreeCAD instance. To do this you must know the name of the file that the finished translations will be put into. In general this is the name of the module you are working on, an underscore, the language code, and ".ts". For example, "PartDesign_es-ES.ts" is the Spanish (Spain) translation file for the Part Design workbench. An exception is the code in `src/Gui`, which is FreeCAD_xx.ts (where xx is the language code).
110
128
111
129
For testing purposes, choose a language you are familiar with (or at least, can navigate well enough to deactivate when you are done testing!), and copy the file generated by lupdate into the appropriate filename. Locate the string you want to test:
Next, this file must be converted to a `*.qm` file using the `lrelease` tool (distributed with Qt). Finally, place the generated QM file in the same location as your user.cfg file, in a subdirectory called "translations", then switch FreeCAD to the language you chose to test with. Your translated string should appear.
0 commit comments