All class methods related to context help start with the common pattern context _help in their names. It is easy to get all occurences in the code with the following command (example):
grep -F context_help `find . -name '*.[Ch]' -print` |
The base functionality is defined in several BC_WindowBase class methods in
guicast/bcwindowbase.C (search on context_help). All BC_Window's and BC_SubWindow's inherit these methods.
For the simplest case of context help definition, it is sufficient to add the call to context_help_set_keyword() in the most inclusive widget constructor. If Alt/h is pressed with the mouse over this widget's window, its keypress_event() method (inherited from BC_WindowBase) will catch this hotkey, fetch the keyphrase defined by context_help_set_keyword() and call the doc/ContextManual.pl script with this keyphrase. Then ContextManual.pl script does the whole processing of the keyphrase given and calls web browser to display the found HTML manual page. The browser is called in the background to prevent from blocking the calling CINELERRA-GG thread.
An example from cinelerra/zoombar.C:
ZoomBar::ZoomBar(MWindow *mwindow, MWindowGUI *gui) : BC_SubWindow(...) { this->gui = gui; this->mwindow = mwindow; context_help_set_keyword("Zoom Panel"); } |
If Alt/h is pressed with the mouse over some subwindow (arbitrary depth) of the context_help_set_keyword() caller, the keypress_event() method of that subwindow catches the hotkey. Its own context help keyword, probably, will be empty. In this case the whole widget hierarchy is traced up to top_level widget, their context help keywords are checked, and the first nonempty keyword is used for context help.
This approach allows us to define the help keyword common to the whole dialog window with a bunch of diverse buttons with a single call to context_help_set _keyword(), without placing such a call into each button constructor. And at the same time, this approach allows to assign different help keywords to GUI elements belonging to the same window but documented in different manual pages.
MWindowGUI::MWindowGUI(MWindow *mwindow) : BC_Window(_(PROGRAM_NAME ": Program"), ...) { this->mwindow = mwindow; ... context_help_set_keyword("Program Window"); } ... FFMpegToggle::FFMpegToggle(MWindow *mwindow, MButtons *mbuttons, int x, int y) : BC_Toggle(...) { this->mwindow = mwindow; this->mbuttons = mbuttons; set_tooltip(get_value() ? FFMPEG_EARLY_TIP : FFMPEG_LATE_TIP); context_help_set_keyword("FFmpeg Early Probe Explanation"); } ... StackButton::StackButton(MWindow *mwindow, int x, int y) : BC_GenericButton(x, y, mwindow->theme->stack_button_w, "0") { this->mwindow = mwindow; set_tooltip(_("Close EDL")); context_help_set_keyword("OpenEDL"); } ... ProxyToggle::ProxyToggle(MWindow *mwindow, MButtons *mbuttons, int x, int y) : BC_Toggle(...) { this->mwindow = mwindow; this->mbuttons = mbuttons; ... context_help_set_keyword("Proxy"); } |
An example with context_help_check_and_show() from cinelerra/mbuttons.C:
int MButtons::keypress_event() { int result = 0; if(!result) { result = transport->keypress_event(); } if(!result) { result = context_help_check_and_show(); } return result; } |
All the keypress handlers are not equal, therefore we provide different variants of the methods context_help_check_and_show() and context_help_show() (the latter for explicit checking on hotkey).
An example with context_help_show() from cinelerra/editpanel.C:
int EditPanelTcInt::keypress_event() { if( get_keypress() == 'h' && alt_down() ) { context_help_show("Align Timecodes"); return 1; } ...further processing... return 1; } |
A single example of much more sophisticated keypress_event() handler can be found in cinelerra/trackcanvas.C (search on context_help). The problem here was to track the particular object drawn on the canvas to figure out whose context help is to be requested. Another rare example of difficulty may appear when context help is desired for some GUI object which is not subclassed from BC_WindowBase.
ContextManual.pl looks for occurence of keyphrases in the following order:
Keyphrase matching is tried first exact and case sensitive, then partially and case insensitive. The special keyword TOC shows Contents, IDX shows Index. If the keyword starts with FILE:, the filename after FILE: is extracted and that file is shown. You can look in the ContextManual.pl script text.
For debugging purposes the script can be called from command line. For this to work, the environment variable $CIN_DAT has to be set to the parent directory of doc.
In the simplest case, nothing has to be done at all. The plugin context help functionality introduced in cinelerra/pluginclient.C automatically assigns context help keyword from the plugin's title for all plugins subclassed from PluginClient. For this to work, the manual page documenting the plugin must be entitled identically to the programmatic title of the plugin. A special treatment can be necessary in the following cases:
Crop & Position \\(X\\/Y\\) |
Such a rewriting can be done either in the C++ code or in ContextManual.pl.
One additional explanation about previous user information when plugin tooltips are off. Help for the selected plugin is shown because in this case it would be difficult to figure out, without a visual feedback, which particular item is currently under the mouse.