Commit 0d7cfde0 authored by Genial-O's avatar Genial-O
Browse files

misc: merge release 22.0.0

parents 78b3d445 05c58310
Pipeline #220992 passed with stages
in 1 minute and 26 seconds
......@@ -18,7 +18,7 @@ The second difference is the line:
.. code-block:: cmake
moduleParam(appXml PARAM_LIST config PARAM_VALUES tutoDataServiceBasicConfig)
module_param(appXml PARAM_LIST config PARAM_VALUES tutoDataServiceBasicConfig)
It defines the main configuration to be launched by the application (see :ref:`HowTosCMakeLists.cmake`).
......
......@@ -52,13 +52,13 @@ Last, in XML-based in applications, you will find the line:
.. code-block:: cmake
moduleParam(appXml PARAM_LIST config PARAM_VALUES tutoBasicConfig)
module_param(appXml PARAM_LIST config PARAM_VALUES tutoBasicConfig)
This custom CMake macro allows to pass parameters to a module. The parameters are defined like:
.. code-block:: cmake
moduleParam(<module>
module_param(<module>
PARAM_LIST <param1_name> <param2_name> <param3_name>
PARAM_VALUES <param1_value> <param2_value> <param3_value>
)
......
*************************
How to create a GUI test?
*************************
Writing unit tests is a good practice, but might be not sufficient. Graphical user interface tests can be a good supplement to improve test coverage.
Create a new class that inherits from sight::ui::test::ITest
------------------------------------------------------------
This new class will typically be located in a subdirectory of the tested target, for instance, GUI tests for SightViewer
are located at "apps/SightViewer/test/ui". This class must inherit from ``sight::ui::test::ITest``, which already implements
the setUp and tearDown methods required by CppUnit to correctly handle the application resources.
This class must implement the getProfilePath method, which is the path to the profile.xml file relative to the build
folder. For instance, for SightViewer it would be "share/sight/SightViewer/profile.xml".
Don't forget to use the CppUnit macros in order to register your new test. You should put only one test per class, so
that they can be launched in different processes. Sight doesn't support launching a profile several time in one process.
Write the GUI test body
-----------------------
If your test class inherits from ``sight::ui::test::ITest``, then it is sufficient to call the ``ITest::start`` method with
the name of the test and the code. A minimal test example would be:
.. code-block:: cpp
void GuiTest::test()
{
start("testName",
[](sight::ui::test::Tester& tester)
{
// The most important part: This is were the actual test code must be written.
});
}
This test checks whether the main window shows up and then closes when using the application. A pretty simple test
indeed, the test can be enhanced by adding code in the lambda passed to the Tester::start method call.
Find GUI components in the window
---------------------------------
The goal of a GUI test is to interact with the interface by simulating mouse clicks and key presses for example. To do
so, one must be able to get the GUI components to be interacted with in the first place.
``Tester::take`` allows one to wait for a component to appears. It must be called with the name of that component and a
lambda which returns the awaited component or nullptr if it didn't appear. Most of the time, to get a component will
imply to use the ``QObject::findChild`` method on the main window. This method must be called with the object name of
the component which must be get: the name of the component can be deduced from the plugin.xml of the
application. This object name is typically the ``uid`` of the Sight service. If it is a subcomponent, it would be the
``uid`` of the parent service, followed with a `/` and the name of the subcomponent. For example, let's assume one want
to get the "Load series" button of the SightViewer interface. It is located here:
.. code-block:: xml
<service uid="toolBarView" type="sight::module::ui::base::SToolBar" >
<gui>
<layout>
<menuItem name="Load series" icon="sight::module::ui::flaticons/BlueLoad.svg" /> <!-- Here! -->
<menuItem name="Open PACS" icon="sight::module::ui::flaticons/GreenServerConnected.svg" style="check" />
<separator/>
<!-- ... -->
</layout>
</gui>
<registry>
<menuItem sid="openSeriesDBAct" start="true" />
<menuItem sid="pacsAct" start="true" />
<!-- ... -->
</registry>
</service>
This button name is "Load series" and it is a subcomponent of the "toolBarView" service. So, its object
name is "toolBarView/Load series". To get this button, one may write this:
.. code-block:: cpp
tester.take(
"Load series button",
[&tester]() -> QObject*
{
QAction* action = tester.getMainWindow()->findChild<QAction*>("toolBarView/Load series");
return sight::ui::test::Tester::getWidgetFromAction(action);
});
It is worth to note that SToolBar menuItem are actually QAction, which is some kind of "abstract" component which can't
be interacted with. ``Tester::getWidgetFromAction`` will allow to get the underlying "concrete" component which can be
interacted with.
This method can also be called with another lambda which checks if that component checks a condition. That lambda gets
the component and must return a boolean. It can be useful, for example, to wait for a dialog window to be visible and
fully operational before interacting with it.
.. code-block:: cpp
tester.take<QWidget*>(
"dialog window",
[]() -> QWidget* {return qApp->activeModalWidget();},
[](QWidget* obj) -> bool {return obj->isVisible();}
);
``QApplication::activeModalWidget`` can be used to get the current dialog window.
One may see that the templated version of the method is used here. When using the templated version, the component will
be casted to the templated type before being passed as an argument to the second lambda if the cast succeeds, else
simply discards the component. This is mostly for convenience, to avoid having to do a qobject_cast in the provided
lambda and having to deal with the failed cast case.
The tester will wait up to 5 seconds by default for the component to appear, this might be modified with a third
parameter, the number of milliseconds to wait for the component. It can be provided as the multiple of the default
timeout, for example ``10000`` and ``sight::ui::test::Tester::DEFAULT_TIMEOUT*2`` are equivalent.
.. code-block:: cpp
tester.take(
"Load series button",
[&tester]() -> QObject*
{
QAction* action = tester.getMainWindow()->findChild<QAction*>("toolBarView/Load series");
return sight::ui::test::Tester::getWidgetFromAction(action);
}, sight::ui::test::alwaysTrue, sight::ui::test::Tester::DEFAULT_TIMEOUT*2);
This timeout is the fourth parameter, which means you must provide the third one, the condition lambda, in order to call
that method. ``sight::ui::test::alwaysTrue`` can be used to always accept the component.
When using ``Tester::take`` and the component doesn't appear (or appears but doesn't verify the condition of the
condition lambda) and the timeout is reached, then the test fails. There are two other variants. The first one is
``Tester::maybeTake``. It is similar to ``Tester::take``, but the test won't fail if the component doesn't appear.
Instead, the next commands are ignored, until the next ``Tester::take``. This can be useful, for example, when a dialog
might appear in certain circonstances and must be dealt with, but the test should continue as normal if it doesn't
appear. For example, the following will wait for a dialog window and click on a button if it appears, and simply
continue if it doesn't appear.
.. code-block:: cpp
tester.maybeTake(
"dialog window which may not appear",
[]() -> QObject* {return qApp->activeModalWidget();});
tester.yields("ok button", [](QObject* old) -> QObject* {return old->findChildren<QPushButton*>()[0];});
tester.interact(std::make_unique<sight::ui::test::MouseClick>());
``Tester::yields`` is close in meaning to ``Tester::take``, with a few differences: Firstly, the first lambda passed to
the method takes a parameter, which is the current graphic component, the one which is about to be replaced. Secondly,
when a ``Tester::maybeTake`` fails, ``Tester::yields`` won't be executed, as opposed to ``Tester::take``. Finally, the
error message is slightly different if the component doesn't appear, there is an emphasis on the fact that the component
appears thanks to the previous one.
Interact with GUI components
----------------------------
The ``Tester::take``, ``Tester::maybeTake`` and ``Tester::yields`` methods internally set the current graphic component.
This current graphic component is the argument given to the lambda of the ``Tester::yields`` method, but is also the
target of the interactions of ``Tester::interact``.
There are four Interaction subclasses which can be used as arguments to the ``Tester::interact`` method: ``MouseClick``,
``MouseDrag``, ``KeyboardClick`` and ``KeyboardSequence``. Their names should be self-explaining.
A few examples:
.. code-block:: cpp
// A mouse click with the left button on the center of the widget:
tester.interact(std::make_unique<sight::ui::test::MouseClick>());
// A mouse drag from the left to the right of the widget while holding the left button:
QWidget* widget = tester.get<QWidget*>();
tester.interact(std::make_unique<sight::ui::test::MouseDrag>(sight::ui::test::Tester::leftOf(widget), sight::ui::test::Tester::rightOf(widget));
// Typing "Hello world!", presumably in a text box
tester.interact(std::make_unique<sight::ui::test::KeyboardSequence>("Hello world!");
// Tap on the backspace key
tester.interact(std::make_unique<sight::ui::test::KeyboardClick>(Qt::Key::Key_Backspace);
Verify assertions
-----------------
Naturally, an important aspect of the test is to check whether the feedbacks of the graphical user interface after the
interaction are correct. For example: Is the text contained in the label correct? Did the dialog window close when the
"OK" button was clicked? Was a file created when the "Save" button is clicked, does it have the right format? Does the
image looks like what it is supposed to look like?
The method ``Tester::doubt`` exists to verify assertions. Its first parameter is the name of the assertion and the
second is a lambda which takes the current graphic component and should return true if the assertion is verified and
false if not. If the assertion is false, ``Tester::doubt`` will wait up to 5 seconds by default for it to become true.
This timeout may be modified with a third parameter, like in the ``Tester::take``, ``Tester::maybeTake`` and
``Tester::yields`` methods.
A few examples:
.. code-block:: cpp
// Check whether a file was created
tester.doubt("the file was created", [](QObject*) -> bool {return std::filesystem::exists("the_file.txt");});
// Check whether two images (an actual and a reference) are similar
compareImages("referenceImage.png", "actualImage.png");
``ITest::compareImages`` is a convenient method to check whether two images are similar. It uses the
``Tester::compareImagesMSE``, ``Tester::compareImagesHistogram``, ``Tester::compareImagesCorrelation`` and
``Tester::compareImagesVoodoo`` methods behind the scenes to achieve this, those methods can be called directly instead.
In order to test assertions on a graphical component, the templated version may be used to cast that component to a
particular type. If the cast fails, the whole test fails as well.
A few examples:
.. code-block:: cpp
// Check whether the text contained in a label is correct
tester.doubt<QLabel*>("the text contained in a label is correct", [](QLabel* label) -> bool {return label->text() == "correct";});
// Check whether the a dialog window is closed
tester.doubt<QWidget*>("the dialog window is closed", [](QWidget* dialog) -> bool {return !dialog->isVisible();});
......@@ -11,3 +11,4 @@ How-Tos
ApplicationCreation.rst
Troubleshooting.rst
QtCreatorSetup.rst
GuiTestCreation.rst
......@@ -41,7 +41,7 @@ If not already installed (please, note the recommended version):
.. code:: bash
$ sudo apt install build-essential ninja-build python3 git git-lfs
$ sudo apt install build-essential ninja-build git git-lfs
For an up-to-date CMake:
......@@ -53,30 +53,12 @@ If not already installed (please, note the recommended version):
.. code:: bash
$ sudo apt install build-essential python3 iputils-ping git git-lfs sudo ssh \
xvfb clang clang-tidy clang-tools git-restore-mtime graphviz doxygen \
cmake-format ccache ninja-build zstd gnuplot uncrustify keyutils \
cppcheck valgrind valgrind-mpi gdb gdbserver glslang-tools gcovr \
libfontconfig1-dev libfreetype6-dev libiconv-hook-dev libpng-dev \
libjpeg-turbo8-dev libtiff5-dev libxml2-dev libexpat1-dev libicu-dev \
libopengl-dev libglew-dev libssl-dev libudev-dev libusb-dev libusb-1.0-0-dev\
libavcodec-dev libavutil-dev libavformat-dev libswscale-dev \
libswresample-dev libavcodec-extra ffmpeg libboost-all-dev zlib1g-dev\
libcppunit-dev libhdf5-dev libqt5opengl5-dev libqt5x11extras5-dev\
libqt5multimedia5-plugins qttools5-dev qtmultimedia5-dev qt3d5-dev \
qt3d-assimpsceneimport-plugin qt3d-defaultgeometryloader-plugin \
qt3d-gltfsceneio-plugin qt3d-scene2d-plugin qtquickcontrols2-5-dev \
libvtk9-dev libvtk9-qt-dev libgdcm-dev libvtkgdcm-tools libinsighttoolkit4-dev dcmtk \
libann-dev libglm-dev libogre-1.12-dev libopencv-dev libceres-dev \
libva-dev libvdpau-dev libopenni2-dev libarchive-dev libyaml-cpp-dev \
libopenigtlink-dev nlohmann-json3-dev libcpprest-dev libgrpc++-dev \
libomp-dev lld lldb protobuf-compiler protobuf-compiler-grpc \
Ogre package is currently bugged and need a little help to allow CMake to use it:
.. code:: bash
$ sudo touch /usr/lib/x86_64-linux-gnu/libOgreGLSupport.a
$ sudo apt install dcmtk libarchive-dev libboost-all-dev libceres-dev libcppunit-dev \
libexpat1-dev libfftw3-dev libgdcm-dev libglm-dev libinsighttoolkit5-dev \
libogre-1.12-dev libopencv-dev libopenigtlink-dev libqt5opengl5-dev \
libqt5x11extras5-dev libvtk9-dev libvtkgdcm-dev libvtk9-qt-dev \
qt3d5-dev qtmultimedia5-dev qtquickcontrols2-5-dev qttools5-dev zlib1g-dev zstd \
libpng-dev libtiff5-dev libhdf5-dev libann-dev
The last step is optional, but required to build integrated documentation:
......
......@@ -16,13 +16,13 @@ An activity is defined by implementing the extension ``sight::activity::extensio
<desc>Activity description ...</desc>
<icon>media_0-1/icons/icon-3D.png</icon>
<requirements>
<requirement name="param1" type="sight::data::Image" /> <!-- defaults : minOccurs = 1, maxOccurs = 1-->
<requirement name="param2" type="sight::data::Mesh" maxOccurs="3" >
<requirement name="image" type="sight::data::Image" /> <!-- defaults : minOccurs = 1, maxOccurs = 1-->
<requirement name="mesh1" type="sight::data::Mesh" maxOccurs="3" >
<key>Item1</key>
<key>Item2</key>
<key>Item3</key>
</requirement>
<requirement name="param3" type="sight::data::Mesh" maxOccurs="*" container="vector" />
<requirement name="mesh2" type="sight::data::Mesh" maxOccurs="*" container="vector" />
<requirement name="imageSeries" type="sight::data::ImageSeries" minOccurs="0" maxOccurs="2" />
<requirement name="modelSeries" type="sight::data::ModelSeries" minOccurs="1" maxOccurs="1">
<desc>Description of the required data....</desc>
......@@ -34,13 +34,7 @@ An activity is defined by implementing the extension ``sight::activity::extensio
</requirements>
<builder>sight::activity::builder::ActivitySeries</builder>
<validator>sight::activity::validator::ImageProperties</validator>
<appConfig id="myAppConfigId">
<parameters>
<parameter replace="registeredImageUid" by="@values.param1" />
<parameter replace="orientation" by="frontal" />
<!-- ...-->
</parameters>
</appConfig>
<appConfig id="myAppConfigId" />
</extension>
......@@ -55,7 +49,7 @@ The activity parameters are (in the following order):
- **requirement**: a required data.
- name:
Key used to add the data in the activity Composite.
Name of the parameter, as defined in the AppConfig.
- type:
The data type (ex: ``sight::data::ImageSeries``).
......@@ -100,14 +94,6 @@ The activity parameters are (in the following order):
defines the AppConfig to launch and its parameters. For Qml activities, it represents the filename of the Qml file
containing the activity. This file must be in the same module as the activity.
- parameters (optional): List of parameters that need to be replaced by a string value.
- parameter (optional): replace the parameter by a given string.
- replace: name of the parameter as defined in the AppConfig
- by: defines the string that will replace the parameter name. It must be a simple string (ex. "frontal").
There are currently three ways to launch an activity.
From a selection of Series contained in a Vector
......
......@@ -7,41 +7,39 @@ Overview
------------------------
A generic scene in Sight is a feature to visualize elements like meshes or images in a scene.
The scene is based on VTK. The generic scene is universal and therefore applicable for diverse visualization tasks.
It can be seen as fusion of a negatoscope and the 3D model visualization.
It uses the Ogre3d library as a rendering engine. The generic scene is universal and therefore applicable for diverse
visualization tasks.
Manager
Main rendering service
------------------------
The ``SRender`` is the manager service of the VTK scene.
Its main task is to instantiate a VTK context (``vtkRender`` and ``vtkRenderWindow``).
The service ``sight::viz::scene3d::SRender`` is the manager of the 3D scene. Its main task is to instantiate an OpenGL context.
In addition, it configures the rendering properties and describes a list of *adaptors*,
which are dedicated services that render Sight data into this rendering context.
.. code-block:: xml
<service uid="generiSceneUID" type="::fwRenderVTK::SRender" >
<scene renderMode="auto|timer|none" offScreen="imageKey" width="1920" height="1080">
<service uid="generiSceneUID" type="sight::viz::scene3d::SRender" >
<scene renderMode="auto|sync" offScreen="imageKey" width="1920" height="1080">
<renderer id="myRenderer" layer="0" background="0.0" />
<vtkObject id="transform" class="vtkTransform" />
<picker id="negatodefault" vtkclass="fwVtkCellPicker" />
<layer id="..." order="1" />
<layer id="..." order="2" />
<adaptor uid="meshAdaptor" />
<adaptor uid="imageAdaptor" />
<adaptor uid="..."/>
<adaptor uid="..."/>
</scene>
<fps>30</fps><!-- used if renderMode=="timer" -->
</service>
renderMode (optional, "auto" by default)
This attribute is forwarded to all adaptors. For each adaptor, if renderMode="auto", the scene is automatically
rendered after doStart, doUpdate, doSwap, doStop and m_vtkPipelineModified=true. If renderMode="timer" the scene is
rendered at N frame per seconds (N is defined by **fps** tag). If renderMode="none" you should call 'render' slot to
render the scene.
This attribute is forwarded to all adaptors. In the "auto" mode, each adaptor may then trigger a rendering request
when it updates, then the system will render a new frame as soon as possible. The mode "sync" is rather designed to
allow the application to request a rendering, when its update loop is done. Most of the time, this is done when
all adaptors are first updated. The tutorial :ref:`TutorialsTuto17SimpleAR` shows how to achieve this.
offScreen (optional):
Key of the image used for off screen render
Key of the image used for off screen rendering
width (optional, "1280" by default):
Width for off screen render
......@@ -53,24 +51,12 @@ renderer
Defines a renderer. At least one renderer is mandatory, but there can be multiple renderer on different layers.
- **id** (mandatory): the identifier of the renderer
- **layer** (optional): defines the layer of the vtkRenderer. This is only used if there are layered renderers.
- **layer** (optional): defines the layer of the renderer.
- **background** (optional): the background color of the rendering screen.
The color value can be defined as a grey level value (ex . 1.0 for white)
or as a hexadecimal value (ex : \#ffffff for white).
vtkObject
Represents a vtk object. It is usually used for vtkTransform or vtkImageBlend.
- **id** (mandatory): the identifier of the vtkObject
- **class** (mandatory): the classname of the vtkObject to create. For example vtkTransform, vtkImageBlend, ...
picker
Represents a picker.
- **id** (mandatory): the identifier of the picker
- **vtkclass** (optional, by default vtkCellPicker): the classname of the picker to create.
adaptor
Defines the adaptors to display in the scene.
......@@ -79,9 +65,9 @@ adaptor
Adaptor
-------------
An adaptor (inherited from ``::fwRenderVTK::IAdaptor``) is a service to manipulate or display a sight data.
Services representing an adaptor are managed by a generic scene (``::fwRenderVTK::SRender``).
The adaptors are the gateway between Sight objects and VTK objects.
An adaptor (inherited from ``sight::viz::scene3d::IAdaptor``) is a service to manipulate or display a sight data.
Services representing an adaptor are managed by a generic scene (``sight::viz::scene3d::SRender``).
The adaptors are the gateway between Sight objects and Ogre objects.
To respect the principles of the framework, adaptors are kept as generic as possible.
Therefore they are reusable in other applications or even adaptors as sub-services.
......@@ -90,29 +76,29 @@ As usual, an adaptor needs to implement the methods ``configuring``, ``starting`
.. code-block:: cpp
class MyAdaptor : public ::fwRenderVTK::IAdaptor
class MyAdaptor : public sight::viz::scene3d::IAdaptor
{
public:
fwCoreServiceClassDefinitionsMacro ( (MyAdaptor)(::fwRenderVTK::IAdaptor) );
SIGHT_DECLARE_SERVICE(MyAdaptor, sight::viz::scene3d::IAdaptor);
protected:
/// Parse the adaptor "config" tag
void configuring() override;
/// Initialize the vtk pipeline (actor, mapper, ...)
/// Initialize the pipeline (scene nodes, material, , ...)
void starting() override;
/// Clear the vtk pipeline
/// Clear the pipeline
void stopping() override;
/// Update the pipeline from the current object
void updating() override;
};
To ease the configuration and the link with the ``::fwRenderVTK::SRender``, the ``configuring`` and ``starting``
To ease the configuration and the link with the ``sight::viz::scene3d::SRender``, the ``configuring`` and ``starting``
should contain this minimal code:
.. code-block:: cpp
......@@ -129,7 +115,7 @@ should contain this minimal code:
...
// Request ::fwRenderVTK::SRender to trigger a rendering when it is ready
// Request sight::viz::scene3d::SRender to trigger a rendering when it is ready
this->requestRender();
}
......@@ -138,9 +124,9 @@ Adaptors are configured and started like other services in the xml since **Sight
.. code-block:: xml
<service uid="meshAdaptor" type="::visuVTKAdaptor::SMesh" autoConnect="yes">
<in key="mesh" uid="meshUID" />
<config renderer="default" picker="" uvgen="sphere" />
<service uid="meshAdaptor" type="sight::module::viz::scene3d::adaptor::SMesh" >
<in key="mesh" uid="..." />
<config layer="..." transform="..." visible="true" materialName="..." shadingMode="phong" />
</service>
...
......
......@@ -50,9 +50,9 @@ The CMakeLists.txt is parsed by CMake_. For an application, it should contain th
module_service # Service base module
)
# The ``moduleParam`` line defines the parameters to set for a module, here it defines the configuration
# The ``module_param`` line defines the parameters to set for a module, here it defines the configuration
# to launch by the appXML module, i.e. the application configuration.
moduleParam(
module_param(
module_appXml
PARAM_LIST
config
......
......@@ -45,9 +45,9 @@ This file describes the project information and requirements :
module_viz_sample # Loads basic rendering services for images and meshes.
)
# The ``moduleParam`` line defines the parameters to set for a module, here it defines the configuration
# The ``module_param`` line defines the parameters to set for a module, here it defines the configuration
# to launch by the appXML module, i.e. the application configuration.
moduleParam(
module_param(
module_appXml
PARAM_LIST
config
......
......@@ -46,9 +46,9 @@ This file describes the project information and requirements :
module_viz_sample # Loads basic rendering services for images and meshes.
)
# The ``moduleParam`` line defines the parameters to set for a module, here it defines the configuration
# The ``module_param`` line defines the parameters to set for a module, here it defines the configuration
# to launch by the appXML module, i.e. the application configuration.
moduleParam(
module_param(
module_appXml
PARAM_LIST
config
......
......@@ -46,9 +46,9 @@ This file describes the project information and requirements :
module_viz_sample # Loads basic rendering services for images and meshes.
)
# The ``moduleParam`` line defines the parameters to set for a module, here it defines the configuration
# The ``module_param`` line defines the parameters to set for a module, here it defines the configuration
# to launch by the appXML module, i.e. the application configuration.
moduleParam(
module_param(
module_appXml
PARAM_LIST
config
......@@ -57,7 +57,7 @@ This file describes the project information and requirements :
)
# Allow dark theme via module_ui_qt
moduleParam(
module_param(
module_ui_qt
PARAM_LIST
resource
......
......@@ -47,9 +47,9 @@ This file describes the project information and requirements :
module_filter_mesh # Provides services to generate a mesh from an image.
)
# The ``moduleParam`` line defines the parameters to set for a module, here it defines the configuration
# The ``module_param`` line defines the parameters to set for a module, here it defines the configuration
# to launch by the appXML module, i.e. the application configuration.
moduleParam(
module_param(
module_appXml
PARAM_LIST
config
......@@ -58,7 +58,7 @@ This file describes the project information and requirements :
)
# Allow dark theme via module_ui_qt
moduleParam(
module_param(
module_ui_qt
PARAM_LIST
resource
......
......@@ -50,9 +50,9 @@ This file describes the project information and requirements :
module_filter_image # Contains the threshold functionality
)
# The ``moduleParam`` line defines the parameters to set for a module, here it defines the configuration
# The ``module_param`` line defines the parameters to set for a module, here it defines the configuration
# to launch by the appXML module, i.e. the application configuration.
moduleParam(
module_param(
module_appXml
PARAM_LIST
config
......@@ -61,7 +61,7 @@ This file describes the project information and requirements :
)
# Allow dark theme via module_ui_qt
moduleParam(
module_param(
module_ui_qt
PARAM_LIST
resource
......@@ -84,7 +84,7 @@ This file is in the ``rc/`` directory of the application. It defines the service
.. code-block:: xml
<plugin id="Tuto06Filter" >
<plugin id="Tuto06Filter" >
<requirement id="sight::module::service" />
<requirement id="sight::module::ui::qt" />
......@@ -181,25 +181,13 @@ This file is in the ``rc/`` directory of the application. It defines the service
<service uid="quitAct" type="sight::module::ui::base::SQuit" />
<!-- Action to open image file: call update on image reader service -->
<service uid="openImageAct" type="sight::module::ui::base::com::SSlotCaller" >
<slots>
<slot>imageReaderSrv/update</slot>
</slots>
</service>
<service uid="openImageAct" type="sight::module::ui::base::SAction" />
<!-- Action apply threshold filter: call update on threshold filter service -->
<service uid="imageFilterAct" type="sight::module::ui::base::com::SSlotCaller" >
<slots>
<slot>imageFilterSrv/update</slot>
</slots>
</service>
<service uid="imageFilterAct" type="sight::module::ui::base::SAction" />
<!-- Action apply flip filter: call 'flipAxisY' slot on flip service -->
<service uid="imageFlipperAct" type="sight::module::ui::base::com::SSlotCaller" >
<slots>
<slot>imageFlipperSrv/flipAxisY</slot>
</slots>
</service>
<service uid="imageFlipperAct" type="sight::module::ui::base::SAction" />
<!-- ******************************* Services ***************************************** -->
......@@ -252,6 +240,21 @@ This file is in the ``rc/`` directory of the application. It defines the service
<!-- ******************************* Start services ***************************************** -->
<connect>
<signal>openImageAct/updated</signal>
<slot>imageReaderSrv/update</slot>
</connect>
<connect>
<signal>imageFilterAct/updated</signal>
<slot>imageFilterSrv/update</slot>
</connect>
<connect>
<signal>imageFlipperAct/updated</signal>
<slot>imageFlipperSrv/flipAxisY</slot>
</connect>