Skip to content
Snippets Groups Projects
Commit 70a46102 authored by tobiglaser's avatar tobiglaser
Browse files

add to API documentation + setPlotTheme RT

parent 0d08a63b
No related branches found
No related tags found
No related merge requests found
# How to add a new function to the cute-API
To add a new function to the cute Interface, follow these steps: To add a new function to the cute Interface, follow these steps:
1. Declare the function in cute.h with `DYNAMIC`. 1. Declare the function in cute.h with `DYNAMIC`.
```
```cpp
void DYNAMIC setPlotTheme(int themeNumber); void DYNAMIC setPlotTheme(int themeNumber);
``` ```
2. Define the function in cute.cpp. Most likely you just funnel the call and it's parameters into the `CuteControl`-Singleton, to then be able to use Qt's signals and slots. 2. Define the function in cute.cpp. Most likely you just funnel the call and it's parameters into the `CuteControl`-Singleton, to then be able to use Qt's signals and slots.
```
```cpp
void cute::setPlotTheme(int themeNumber) void cute::setPlotTheme(int themeNumber)
{ {
CuteControl::get().setPlotTheme(themeNumber); CuteControl::get().setPlotTheme(themeNumber);
} }
``` ```
3. Define a `signal` in CuteControl, corresponding to your function. To avoid naming conflicts, I used the prefix `s_` in CuteControl. `signals` are always void functions, they are defined by the Qt Meta Object Compiler during the compilation. Think of them as part of the Observer-Pattern, they send a `signal` to all connected `slots`. 3. Define a `signal` in CuteControl, corresponding to your function. To avoid naming conflicts, I used the prefix `s_` in CuteControl. `signals` are always void functions, they are defined by the Qt Meta Object Compiler during the compilation. Think of them as part of the Observer-Pattern, they send a `signal` to all connected `slots`.
```
```cpp
void s_setPlotTheme(int); void s_setPlotTheme(int);
``` ```
4. Declare and define the member function publically in CuteControl. Since Qt's built in types, like `QString` don't require extra steps to be able use them in `signals`, it is advisable to any conversions here. Then `emit` a your `signal`, which will carry the necessary information over the thread boundary. `emit` may be thought of as `fireX()` in the Observer-Pattern. 4. Declare and define the member function publically in CuteControl. Since Qt's built in types, like `QString` don't require extra steps to be able use them in `signals`, it is advisable to any conversions here. Then `emit` a your `signal`, which will carry the necessary information over the thread boundary. `emit` may be thought of as `fireX()` in the Observer-Pattern.
```
```cpp
void setChartTheme(int themeNumber) void setChartTheme(int themeNumber)
{ {
emit s_setPlotTheme(themeNumber); emit s_setPlotTheme(themeNumber);
} }
``` ```
5. Now define the fitting `slot` in `control.h`, which will be used to receive your `signal`. In the Observer-Pattern, this is the listener function. Technically it only needs to be `public`, if you want to connect to or call it from another class. 5. Now define the fitting `slot` in `control.h`, which will be used to receive your `signal`. In the Observer-Pattern, this is the listener function. Technically it only needs to be `public`, if you want to connect to or call it from another class.
```
```cpp
public slots: public slots:
void setPlotTheme(int themeNumber); void setPlotTheme(int themeNumber);
``` ```
6. Now define the `slot` like a regular function in `control.cpp`. Here is *finally*, where you implementation should be placed. The View lives in the `MainWindow` member `_w`. In this case, I call a member function of the View. 6. Now define the `slot` like a regular function in `control.cpp`. Here is *finally*, where you implementation should be placed. The View lives in the `MainWindow` member `_w`. In this case, I call a member function of the View.
```
```cpp
void Control::setPlotTheme(int themeNumber) void Control::setPlotTheme(int themeNumber)
{ {
_w->changeChartTheme(themeNumber); _w->changeChartTheme(themeNumber);
} }
``` ```
7. Lastly, connect `signal` and `slot` in `makeConnections()` of the `Control`. This completes the Observer-Pattern, by subscribing `Control` to `CuteControl`. 7. Lastly, connect `signal` and `slot` in `makeConnections()` of the `Control`. This completes the Observer-Pattern, by subscribing `Control` to `CuteControl`.
Connections are pretty resilient. They check if the listener still exists, as well as in which thread they are. If the listener is in another thread, the `signal` will be queued in the threads corresponding event queue. Connections are pretty resilient. They check if the listener still exists, as well as in which thread they are. If the listener is in another thread, the `signal` will be queued in the threads corresponding event queue.
With clang, this command has to be quite verbose, the basic pattern is: `Sender, &signal, Receiver, &slot` With clang, this command has to be quite verbose, the basic pattern is: `Sender, &signal, Receiver, &slot`
```
```cpp
connect(cc, &CuteControl::s_setPlotTheme, this, &Control::setPlotTheme); connect(cc, &CuteControl::s_setPlotTheme, this, &Control::setPlotTheme);
``` ```
8. Almost forgot: Of course add some Doxygen. At least in `cute.h`. 8. Almost forgot: Of course add some Doxygen. At least in `cute.h`.
9. Build.
Up to here it works when using the compiled import library `libcute.dll.a`. If you want to be able to load the dll at runtime, continue.
# TODO 10. The linker exports a `cute.def` file in the build directory. In this file, search the mangled function name. It contains the function name and it's namespace, so you can use Ctrl+F to find it.
## without importlib Copy this string and paste it into the `cute.def` file in the source directory. Here, create an alias with the plain function name.
This way, the `cuteImporter.cpp` is simpler to read. It is also possible to use the mangled name there.
```cpp
setPlotTheme=_ZN4cute12setPlotThemeEi setPlotTheme=_ZN4cute12setPlotThemeEi
```
11. Now, in `cuteImporter.cpp` do the following:
1. In the anonymous namespace, create a `typedef` for an appropriate function pointer to your function.
```cpp
typedef void (*t_setPlotTheme)(int);
```
2. Create an empty function pointer .
```cpp
t_setPlotTheme setPlotThemeImpl = nullptr;
```
3. Populate the function pointer by retreiving the Address inside the dynamic library and casting it to the type defined above. Here the alias from `cute.def` is used.
```cpp
setPlotThemeImpl = reinterpret_cast<t_setPlotTheme>(GetProcAddress(hDll, "setPlotTheme"));
```
4. Check if you got a pointer by adding it to the if-condition with a logical boolean operator `&&`.
```cpp
if(
// ...
setPlotThemeImpl &&
// ...
)
```
5. Define the function you declared in `cute.h`. This definition calls the populated function pointer and returns it's result. Since it has been checked beforehand, another check can be neglected here for our purposes.
```cpp
void setPlotTheme(int themeNumber)
{
return setPlotThemeImpl(themeNumber);
}
```
6. Lastly, in `shutdown()` clear the function pointer again. This should not be critical, since the function is only called when the process exits anyway.
```cpp
setPlotThemeImpl = nullptr;
```
12. Done! Now test if it works with the appropriate example. :D
...@@ -79,6 +79,7 @@ void advancedDummy() ...@@ -79,6 +79,7 @@ void advancedDummy()
{ {
std::vector<float> problem1D = cute::getProblemData1D(); std::vector<float> problem1D = cute::getProblemData1D();
cute::logMessage(fvec2str(problem1D)); cute::logMessage(fvec2str(problem1D));
cute::setPlotTheme(problem1D.size() - 1);
std::vector<cute::Point> problem2D = cute::getProblemData2D(); std::vector<cute::Point> problem2D = cute::getProblemData2D();
for (auto &&p : problem2D) for (auto &&p : problem2D)
{ {
... ...
......
...@@ -82,6 +82,7 @@ void advancedDummy() ...@@ -82,6 +82,7 @@ void advancedDummy()
{ {
std::vector<float> problem1D = cute::getProblemData1D(); std::vector<float> problem1D = cute::getProblemData1D();
cute::logMessage(fvec2str(problem1D)); cute::logMessage(fvec2str(problem1D));
cute::setPlotTheme(problem1D.size() - 1);
std::vector<cute::Point> problem2D = cute::getProblemData2D(); std::vector<cute::Point> problem2D = cute::getProblemData2D();
for (auto &&p : problem2D) for (auto &&p : problem2D)
{ {
... ...
......
...@@ -9,6 +9,7 @@ namespace { ...@@ -9,6 +9,7 @@ namespace {
typedef void (*t_setProgress)(int); typedef void (*t_setProgress)(int);
typedef void (*t_logMessage)(const std::string&); typedef void (*t_logMessage)(const std::string&);
typedef void (*t_setStatusMessage)(const std::string&, int); typedef void (*t_setStatusMessage)(const std::string&, int);
typedef void (*t_setPlotTheme)(int);
typedef void (*t_enableAutorun)(bool); typedef void (*t_enableAutorun)(bool);
typedef void (*t_setProblemFile)(const std::string&); typedef void (*t_setProblemFile)(const std::string&);
typedef void (*t_setProblemSize)(int); typedef void (*t_setProblemSize)(int);
...@@ -22,6 +23,7 @@ namespace { ...@@ -22,6 +23,7 @@ namespace {
t_setProgress setProgressImpl = nullptr; t_setProgress setProgressImpl = nullptr;
t_logMessage logMessageImpl = nullptr; t_logMessage logMessageImpl = nullptr;
t_setStatusMessage setStatusMessageImpl = nullptr; t_setStatusMessage setStatusMessageImpl = nullptr;
t_setPlotTheme setPlotThemeImpl = nullptr;
t_enableAutorun enableAutorunImpl = nullptr; t_enableAutorun enableAutorunImpl = nullptr;
t_setProblemFile setProblemFileImpl = nullptr; t_setProblemFile setProblemFileImpl = nullptr;
t_setProblemSize setProblemSizeImpl = nullptr; t_setProblemSize setProblemSizeImpl = nullptr;
...@@ -46,6 +48,7 @@ namespace cute { ...@@ -46,6 +48,7 @@ namespace cute {
// your code for which the warning gets suppressed // your code for which the warning gets suppressed
setProgressImpl = reinterpret_cast<t_setProgress>(GetProcAddress(hDll, "setProgress")); setProgressImpl = reinterpret_cast<t_setProgress>(GetProcAddress(hDll, "setProgress"));
setStatusMessageImpl = reinterpret_cast<t_setStatusMessage>(GetProcAddress(hDll, "setStatusMessage")); setStatusMessageImpl = reinterpret_cast<t_setStatusMessage>(GetProcAddress(hDll, "setStatusMessage"));
setPlotThemeImpl = reinterpret_cast<t_setPlotTheme>(GetProcAddress(hDll, "setPlotTheme"));
logMessageImpl = reinterpret_cast<t_logMessage>(GetProcAddress(hDll, "logMessage")); logMessageImpl = reinterpret_cast<t_logMessage>(GetProcAddress(hDll, "logMessage"));
enableAutorunImpl = reinterpret_cast<t_enableAutorun>(GetProcAddress(hDll, "enableAutorun")); enableAutorunImpl = reinterpret_cast<t_enableAutorun>(GetProcAddress(hDll, "enableAutorun"));
setProblemFileImpl = reinterpret_cast<t_setProblemFile>(GetProcAddress(hDll, "setProblemFile")); setProblemFileImpl = reinterpret_cast<t_setProblemFile>(GetProcAddress(hDll, "setProblemFile"));
...@@ -60,10 +63,10 @@ namespace cute { ...@@ -60,10 +63,10 @@ namespace cute {
//#pragma GCC diagnostic pop //#pragma GCC diagnostic pop
// By checking here, we can spare any future checks and if we exit main() on any errors, we can spare us any exception handling. // By checking here, we can spare any future checks and if we exit main() on any errors, we can spare us any exception handling.
if ( if ( setProgressImpl &&
setProgressImpl &&
setStatusMessageImpl && setStatusMessageImpl &&
logMessageImpl && logMessageImpl &&
setPlotThemeImpl &&
enableAutorunImpl && enableAutorunImpl &&
setProblemFileImpl && setProblemFileImpl &&
setProblemSizeImpl && setProblemSizeImpl &&
...@@ -93,6 +96,10 @@ namespace cute { ...@@ -93,6 +96,10 @@ namespace cute {
{ {
return setStatusMessageImpl(message, duration_s); return setStatusMessageImpl(message, duration_s);
} }
void setPlotTheme(int themeNumber)
{
return setPlotThemeImpl(themeNumber);
}
void logMessage(const std::string &message) void logMessage(const std::string &message)
{ {
return logMessageImpl(message); return logMessageImpl(message);
...@@ -142,6 +149,7 @@ namespace cute { ...@@ -142,6 +149,7 @@ namespace cute {
hDll = nullptr; hDll = nullptr;
setProgressImpl = nullptr; setProgressImpl = nullptr;
setStatusMessageImpl = nullptr; setStatusMessageImpl = nullptr;
setPlotThemeImpl = nullptr;
logMessageImpl = nullptr; logMessageImpl = nullptr;
enableAutorunImpl = nullptr; enableAutorunImpl = nullptr;
setProblemFileImpl = nullptr; setProblemFileImpl = nullptr;
... ...
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment