Developing a simple module - 3dct/open_iA GitHub Wiki

Here's a short tutorial on writing a simple open_iA module.

Note: The code shown here is written for work based on our current develop branch (see also our Branching Strategy), so if you get any errors while building (such as addToMenuSorted not found), make sure the open_iA source repository in your Build environment is switched to this branch!

  1. Create a new folder in the modules subdirectory of the open_iA source directory, with the name of your module. Here we will use the name "Test". Make sure that you create all the source files mentioned here in the source directory. For example Visual Studio will typically propose to store files in the binary directory if you have set up an out-of-source build environment, as recommended and as described in our Build Instructions. Note that CMake only detects source files in the source folder when run. Any source files in the binary folder are ignored, and since the project files are recreated, files in the binary folders will be removed from the project on running CMake, in case they were manually added to it before.
  2. In that new subdirectory, we need to create a few files:
  • description.cmake, a file with content like this:

    set(MODULE_DESCRIPTION
        "Test module description"
    )
    

    This file specifies the description of the module, as shown in CMake when hovering over the according Module_... option.

  • Dependencies.cmake, a file with content like this:

    set(DEPENDENCIES_LIBRARIES
    	iA::guibase
    )
    

    This file describes any compilation dependencies of the module, i.e. which libraries and headers it dependes on. In the example above, the module it depends on the guibase library, a core library from the open_iA framework, which provides access to basic GUI functionality.

    For a list of potential core libraries to depend on, and some information on what functionalities they contain, see the code structure overview; each of them resides in a subfolder of the "libs" folder; the iA:guibase used here is an ALIAS for the iAguibase library created from the guibase subfolder; there is such an iA:: prefixed ALIAS for each of the libraries, it is preferred to link to these - the contained :: forces CMake to see the name as a target, which allows for stricter error checking at configure time.

    Note: Only a recent develop branch currently supports the iA:: prefix notation (e.g. iA::guibase) notation; when building older versions, use iAguibase (or, recommended, switch to the newest develop branch); in even older versions (<= 2020.09), iA::guibase was assumed as automatic dependency, the file Dependencies.cmake had slightly different configuration settings, and was optional.

    Through the Dependencies.cmake file, you can also add dependencies to other libraries, such as the CUDA library, should the need arise. See other modules for how to specify dependencies, e.g. the ASTRAReconstruction module with references to the ASTRA toolbox and CUDA.

  • iATestModuleInterface.h, the header file of the module interface:

    #pragma once
    #include <iAGUIModuleInterface.h>
    
    class iATestModuleInterface : public iAGUIModuleInterface
    {
    	Q_OBJECT
    public:
    	void Initialize() override;
    private slots:
    	void testAction();
    };
    

    Note that the class and file need to exactly follow the convention of being named iA<ModuleName>ModuleInterface (with [.h|.cpp] suffix for the files). The needs to be exactly the same (also regarding upper/lowercase!) as the name given to the subdirectory of the "module" folder - as you can see, in our case, ModuleName is 'Test'.

  • iATestModuleInterface.cpp, the implementation for the module interface:

    #include "iATestModuleInterface.h"
    
    #include "iAMainWindow.h"
    
    #include <QAction>
    #include <QMessageBox>
    
    void iATestModuleInterface::Initialize()
    {
    	if (!m_mainWnd)    // if m_mainWnd is not set, we are running in command line mode
    	{
    	    return;        // in that case, we do not do anything as we can not add a menu entry there
    	}
    	QAction * actionTest = new QAction(tr("Test"), m_mainWnd);
    	connect(actionTest, &QAction::triggered, this, &iATestModuleInterface::testAction);
    	// m_mainWnd->makeActionChildDependent(actionTest);   // uncomment this to enable action only if child window is open
    	addToMenuSorted(m_mainWnd->toolsMenu(), actionTest);
    }
    
    void iATestModuleInterface::testAction()
    {
    	QMessageBox::information(m_mainWnd, "Test Module", "This is the Test Module!");
    }
    

    The Initialize method is called when the plugin gets loaded (which happens when the program starts). This is thus the main initialization method of the module. Typically, modules create one or more menu entries here; but also other preparations required for this module could be done there. To put it differently, everything needed to make the functionality of the module available in the GUI needs to be done here. Note that the module can also be initialized from the command line. In this case, the m_mainWnd member variable is not set (nullptr); in that case, no graphical user interface is available. In our simple test module here, we only want to do something if the module is loaded from the graphical user interface; in that case we want to add a menu entry called "Test" to the filters menu, retrieved via the reference to the Main Window, given by the m_mainWnd variable, which is inherited from the iAGUIModuleInterface class. The menu entry is not depending on the availability of an open file; if you want to make the menu entry only be enabled if a file is open, then uncomment the call to m_mainWnd->makeActionChildDependent. The added menu entry is linked to the method testAction via the call to the connect method (inherited from QObject). In the testAction we just open a simple information message box.

  1. With these files created, open CMake, and configure open_iA again. When it finishes, you will see a new option pop up: Module_Test
  2. Check this option and "Generate"
  3. Build open_iA in your preferred environment. A new shared library / dll will be created in the plugins sub-directory of the build folder.
  4. Start open_iA, and open the "Tools" menu. You should see a "Test" menu entry; when you click on this entry, a message box saying "This is the Test Module!" should appear.

Congratulations, you have just finished your first open_iA module!

As a side note, the following files are optionally also considered in our CMake build system:

  • enabled.cmake - executed by CMake if the module is enabled by the user. Can contain scripts for adding test cases for this module, or some other operations that need to be executed in the Configure step only when this module is enabled.
  • precompile.cmake - a list of header files that should be included in the precompiled header if this option is enabled (openiA_PRECOMPILE). See the precompile.cmake in the 4DCT module as an example
  • Additional *.cpp, *.h, *.ui and *.qrc files are also automatically added to the build by our CMake scripts. Just make sure to execute CMake Configure/Generate after you have added them! If you include a *.qrc resource file, you have to initialize it by calling the Q_INIT_RESOURCE macro; see e.g. the Initialize method in the FeatureScout module interface

Of course, this module does not yet do much; it only shows a message.

The simplest useful thing a module can do is to add an image processing filter to open_iA. This is what we will explore in the next section.

Continue to Developing a filter module.

⚠️ **GitHub.com Fallback** ⚠️