Let’s face it: the Hugin codebase has a steep learning curve that is difficult to climb. We’ve had this feedback for years, from the 2007 Google Summer of Code students and earlier. I’ve been around the project for a few years but I still find it difficult to get back into it after taking a break for a while. The solution is known: documentation. Hence one of my first contributions to the project was to drive the effort to document the build.
Documenting the code is a much larger endeavor. Sure we have the (incomplete) doxygen documentation, a good reference, but as dry and interesting and captivating as reading the complete Oxford dictionary end to end. We need a broader description of how the codebase is organized and small tutorials to get new contributors started. I realize that I always scribbled down my little notes when doing things, but never really polished them into proper documentation. Time to change this bad habit. Here is a first simple tutorial: adding a preference to Hugin.
There are four steps involved:
- Edit the GUI
- Set the defaults
- Make the preference widget functional
- Use the preference
Edit the GUI
Hugin uses the wxWidgets GUI toolkit. Layouts can be built in two ways: on the fly by the functional code; or using a declarative language, XRC, an XML derivate. The preferred way for Hugin is to use XRC, Panels are defined in /src/hugin1/hugin/xrc.
There are many tools to edit XRC files. To be honest I have not found one of them that I really like. I edit the XRC files manually, with a simple text editor and a little bit of discipline.
Before proceeding, back up your existing XRC file. For this technique to work, Hugin must be set to display the GUI in the English language. I start Hugin and I look at the GUI layout that I want to change. ./src/hugin1/hugin/xrc/pref_dialog.xrc for the preferences. I find a string that is unique enough to appear only there in this context. Then I open the panel’s XRC and use the editor’s search functionality to zero in on the area of interest.
In the area of interest I first separate visual/logical blocks by adding temporary white spaces and temporary XML comments enclosed in <!– –>. Indentation helps too, but alon it is not enough to keep track of where I am. Remember to clean up after editing, i.e. make sure indentation is correct and remove white spaces and comments.
Usually there is already a similar widget to the one I want to add somewhere else in the code. I look for that widget with the same technique and I copy/adapt its definition. Widgets can have many attributes and they are surrounded by a lot of layout definitions. Detailed stuff that is very important to keep a nice, polished and uniform look. When adding a widget, especially when copying it, it is important to take care of the name attribute. Give it a meaningful name, to avoid duplicates, and to be able to refer to it from the code. Follow the same naming convention as the other widgets names: all_small_caps_underscore_separated_words.
No need to rebuild the application to preview the changes. Just close the application, copy the edited XRC file from ./src/hugin1/hugin/xrc/ to /usr/local/share/hugin/xrc (or wherever the files are installed on your system), restart the application and preview the result. Start the application from a terminal to see diagnostic messages. If the XRC file was badly damaged/malformed, Hugin may crash right after the start, or when the panel is displayed. You can always revert to the backed up version if the edits are beyond repair (you did backup, did you?) and start over again. Making the changes in small incremental steps helps prevent getting into situations beyond repair.
Set the Defaults
Choose a meaningful default for your widget and add it to ./src/hugin1/hugin/config_default.h. Name the default value ALL_CAPS_UNDERSCORE_SEPARATED_WORDS like the other default values. You will find inspiration in the default values around you. It is good practice to add the default value in a place that follows the logical order of preferences grouping in pref_dialog.xrc.
Make the Preferences Widget Functional
Preferences functionality is in ./src/hugin1/hugin/PreferencesDialog.cpp. Here preferences are read/written/reset with cfg->Read() and cfg->Write(), referring to the names you defined above. Note that strings must be encapsulated in the wxT() function, and that here you give (yet) another name to the preference, this time in CamelCaseNoSpaces. Preferences are referred to by this name in the code.
Now it is a good time to test the new preference. Build the code, start the application, go into the Preferences menu edit / change / reset the preference. Quit and restart the application to check that it is really persistent.
Use the Preference
Now you can use your newly created preference everywhere in the code with wxConfigBase::Get()->Read(wxT()). For two practical examples, see the smart undo preference and the file naming convention preference.
The two links above demonstrate another useful technique to dive into the codebase: read commit diffs. Commit diffs show the difference between two revisions. Developers comment such differences in the changelog. By knowing from the changelog what the intended result of the change is, and looking at the (usually not too many) lines of code changed, you can understand how to make similar changes.
I hope this tutorial has helped you demystifying a little bit Hugin’s codebase. If you need any help, the developers read the mailing list and will be happy to help you come on board.