A Step by Step Guide to New Feature Development in CARTA
1. Decide where in the UI the new feature should be located. In this case, adding two additional algorithms, bilinear and bicubic, to the existing nearest neighbor algorithm for generating contours, we will locate the new feature in the image settings window under the contour tab. This means we will need to modify the code in the file: html5/common/skel/source/class/skel/widgets/Image/Contour/GeneratorPage.js.
2. Add the appropriate UI widget to the page. The GeneratorPage.js follows the pattern of most JavaScript objects in CARTA and has an "_init" method where the GUI objects are created. Adding a ComboBox would be appropriate in this case to allow the user to choose from 3 different sampling algorithms. There is already a ComboBox for the "Spacing", so copying the code for the spacing ComboBox and modifying it for a choice of sampling algorithms should work. The first argument to the SelectBox constructor is the command that will be sent to the server in order to change the algorithm and the second argument is the name of the parameter that will be sent. At this point you should be able to see a blank combo box in the UI.
3. Move to the server side and create a CARTA object that will manage the available choices for sampling algorithms. In the directory carta/cpp/core/Data/Image/Contour are the classes that manage Contour state. You will notice a class called ContourSpacingModes that manages the available choices for contour spacing. If you were to copy this class, rename it ContourSamplingAlgorithms, and modify the code to represent the sampling algorithms available your will have completed this task.
4. Because the class that you created, ContourSamplingAlgorithms, should be a singleton (we only need a single list of available sampling algorithms for the whole application), we need to let the object manager know this and create the singleton when the ViewManager starts up. Add the class name to the carta/cpp/care/State/ObjectManager.cpp file in the QList at the top to make it application wide. To instantiate it, add a line
Util::findSingletonObject();
, to the carta/cpp/core/Data/ViewManager.cpp constructor code.
5. Return to the UI and get the list of available sampling algorithms to appear in the ComboBox that you created. For this, you will need to obtain the CARTA id of the ContourSamplingAlgorithms object and register to receive updates of available sampling methods. One method to focus on in the GeneratorPage.js is "_spacingModesChangedCB". This is the callback that takes the available spacing modes from the server and updates the combobox with these choices. You will need to write a similar callback for algorithm choices. You will need to create a shared variable that stores the state of the available sampling algorithms and notifies the callback when there is a change. For spacing modes, this shared variablee is named m_sharedVarSpacing modes. You will see the shared variable declared at the bottom on the class, and you will see it initialized in the constructor. Once the modifications in this step have been correctly accomplished, you should no longer see a blank ComboBox, but one filled in with the available sampling algorithms.
6. Add state for a specific choice of sampling algorithm to the C++ side. The class that manages state for generating contours is carta/cpp/core/Data/Image/Contour/GeneratorState. In the "_initializeState" method of this class you will see a list of (key,value) pairs that represent the state a user can set. Add a state for SAMPLING_ALGORITHM copying the same format as SPACING_MODE. You will also need to modify the "_initializeSingletons" method to obtain an instance of the ContourSamplingAlgorithms class to query for the default sampling algorithm. Add a getter/setter method pair for the sampling algorithm similar to "setSpacing" and "getSpacing". The DataContours class will also need to be modified with appropriate getters and setters since class manages the state of a single set of contours.
7. Add a command for setting the sampling algorithm to the main contour generation class, ContourControls. The commands that the C++ side supports can be found in the "_initializeCallbacks" method. Write a callback similar to the one that uses "setSpacing" for setting the algorithm. You will need to be careful the string command that you use matches exactly the one you used on the JavaScript side, and that the parameter names match as well.
8. Return to the JavaScript side and add the code to correctly set the correct value in the ComboBox and send a command to the server if the user makes another ComboBox selection. You will see a method called "setControls" in GeneratorPage.js. The controls variable that is passed in to the method contains a JSON object representation of the server state. You will need to add a line such as, "this._setSamplingAlgorithm( controls.samplingAlgorithm );" to the method. Then write the method "_setSamplingAlgorithm" to select the server-side value in the combo box. The custom SelectBox will handle sending any user-selected sampling algorithms to the server, as long as you pass it the server-side id of the ContourControls CartaObject. In the "setId" method, this identifier is passed in, and you must add a line to set the id in your samplingCombo. At this point, the server-side value of the sampling algorithm should be selected, and you should be able to send a command to the server to change the algorithm.
9. Make sure the server-side uses the correct algorithm when calculating contours. The cpp/CartaLib/core/Data/Image/Draw/DrawSynchronize class has a referene to an "IContourGeneratorService". You will need to add a method to the IContourGeneratorService for setting the sampling method. Then you will need to implement this method with bilinear and bicubic algorithms. The method "setContours" in the DrawSynchronizer class will need to be modified by adding a line to set the algorithm.