### Providing Help Information

Help information is the information about how to use an application. By describing an application's choices, objects, and interaction techniques, help information can assist users in learning to use a product.

The Open Class Class Library provides an IHelpWindow class that uses either native Windows help (Rich Text Format) or the OS/2 Information Presentation Facility (IPF) to provide help information for applications. The pmCompatible IHelpWindows use IPF based help. On Windows, you can also use RTF help if you do not specify the pmCompatible option.

To view an IPF help file on Windows, use IVIEW.EXE. On OS/2, the executable is VIEW and on Motif it is xview.

You create and associate an IHelpWindow object with one of your application's main windows. The Open Class Class Library also provides an IHelpHandler class to process help window events. When you associate an application window with a help window, help events are dispatched to the help handlers attached to the application window.

To use the IHelpWindow class, you create and associate an IHelpWindow object with one or more of your application's main windows. The help panels displayed by IHelpWindow are written and compiled using tools native to your development environment or provided with the VisualAge C++ product. To present a consistent look and feel for help across development environments, use the IPF help information compiler and runtime. On the Windows environment, you can also display your information using the native Windows help facility. Although the process of generating the help information is different, and the display and interaction of the Windows help facility is different from IPF, you can still use the classes of IHelpWindow to interact with native Windows help. However, some of the IHelpWindow functions have no equivalent for Windows help and therefore return without performing any operation. See the IHelpWindow class in the Open Class Library Reference for information on behavior in the Windows environment.

To use IPF help files, call the following before constructing your IHelpWindow objects:

    IHelpWindow::setDefaultStyle( IHelpWindow::ipfCompatible );

By default, IHelpWindow uses native Windows help.

In some cases, you may want to override the behavior of the help facility. You can attach an IHelpHandler object to a frame window that has been associated with a help window. By default, the IHelpHandler provides meaningful message boxes when odd situations occur, such as the help file not being found. To override this behavior, derive your own class from IHelpHandler and overide the functions you need to change.

#### Creating Help Information

Use the following steps to create IPF help information for your application:

1. Create a file containing the help information.

   Create the source text that displays in your application's help window using the IPF format (.ipf file) for the OS/2 operating system and the IPF/X format (.ipf file) for the Windows and Motif environments. Compile your file into a help file (.hlp file) using the IPFC compiler.

   Refer to the Information Presentation Facility documentation for descriptions of the tags you use to create the source .ipf file.

   For an example of a .ipf source file, see the Hello World version 5 ahellow5.ipf file, which is described in Hello World Version 5: Adding Canvases, a List Box, Native System Functions, and Help.

2. Define the help window title and the help submenu in your resource file. defined in the Windows ahellow5.rc file, as follows:

       STR_HTITLE, "C++ Hello World - Help Window"   //Help window title string

       POPUP     "&Help"                   ,  MI_HELP  ,  RIGHTJUSTIFY
         BEGIN
           MENUITEM  "&General help..."        ,  SC_HELPEXTENDED  /*MIS_SYSCOMMAND*/
           MENUITEM  "&Keys help..."           ,  SC_HELPKEYS  /*MIS_SYSCOMMAND*/
           MENUITEM  "Help &index..."          ,  SC_HELPINDEX  /*MIS_SYSCOMMAND*/
         END

   The AIX and OS/2 .rc file appears as follows:

       STR_HTITLE, "C++ Hello World - Help Window"

       SUBMENU "~Help", MI_HELP, MIS_HELP
         BEGIN
           MENUITEM "~General help...",   SC_HELPEXTENDED, MIS_SYSCOMMAND
           MENUITEM "~Keys help...",      SC_HELPKEYS, MIS_SYSCOMMAND
           MENUITEM "Help ~index...",     SC_HELPINDEX, MIS_SYSCOMMAND
         END

   Applications with .rc files that use the following constants should include the icconst.h file:

                  SC_HELPKEYS
                  SC_HELPINDEX
                  SC_HELPEXTENDED

   MI_HELP is the help menu ID.

   Normally, you specify MIS_HELP for a menu item to cause a help event, rather than a command event, to be posted when the menu item is selected.

   When you specify MIS_HELP (OS/2) or RIGHTJUSTIFY (Windows) for a submenu item, Motif automatically positions the item to the far right of the menu bar. OS/2 PM ignores MIS_HELP specified on submenu items. Windows NT 3.51 ignores RIGHTJUSTIFY specified on submenu items.

   When MIS_SYSCOMMAND is specified with the predefined SC_HELP* IDs, a system command event is generated. The default system command handler recognizes the predefined IDs and shows the appropriate help panel, except for SC_HELPKEYS, which by default does nothing. SC_HELP* IDs are defined in the `<icconst.h>` file. You can override this default processing for SC_HELPKEYS, using an IHelpHandler, which is described in a later step.

3. Define a help table in the resource file.

   The help table defines the relationship between the window ID and the general or contextual panel ID that is defined in the .ipf file. The following help table is defined in the resource file, ahellow5.rc, for Hello World version 5:

       HELPTABLE HELP_TABLE
         BEGIN
           HELPITEM WND_MAIN,        SUBTABLE_MAIN,   100
           HELPITEM WND_TEXTDIALOG,  SUBTABLE_DIALOG, 200
         END

       HELPSUBTABLE SUBTABLE_MAIN                      //Main window help subtable
         BEGIN                                         //
           HELPSUBITEM WND_HELLO, 100                  //Hello static text help ID
           HELPSUBITEM WND_LISTBOX,102                 //List box help ID
           HELPSUBITEM MI_EDIT, 110                    //Edit menu item help ID
           HELPSUBITEM MI_ALIGNMENT, 111               //Alignment menu item help ID
           HELPSUBITEM MI_LEFT, 112                    //Left command help ID
           HELPSUBITEM MI_CENTER, 113                  //Center command help ID
           HELPSUBITEM MI_RIGHT, 114                   //Right command help ID
           HELPSUBITEM MI_TEXT, 199                    //Text command help ID
         END                                           //

       HELPSUBTABLE SUBTABLE_DIALOG                    //Text dialog help subtable
         BEGIN                                         //
           HELPSUBITEM DID_ENTRY, 201                  //Entry field help ID
           HELPSUBITEM DID_OK, 202                     //OK command help ID
           HELPSUBITEM DID_CANCEL, 203                 //Cancel command help ID
         END                                           //

   WND_HELLO and WND_LISTBOX are control IDs, MI_* are menu item IDs, and the DID_* are push button IDs. Each window ID is related to a help panel ID. In the preceding example, WND_MAIN and WND_HELLO both correspond to help panel ID 100. That is, pressing the F1 key in the main window area displays the same help panel as selecting General help... from the Help submenu.

4. Create a help window object for your application window.

   Use the IHelpWindow class to associate help information with an application window. Hello World version 5 defines the private data member, helpWindow, as an IHelpWindow object. It is initialized in the AHelloWindow constructor in ahellow5.cpp using the following statement:

       ,helpWindow(HELP_TABLE,this)

   The first parameter identifies the help table defined in the resource file. The second parameter identifies the application window for which the help is being provided.

   Use the IHelpWindow::addLibraries member function to associate a help file with a help window. The AHelloWindow constructor in Hello World version 5 provides an example:

       helpWindow.addLibraries("ahellow5.hlp");

   You can set the title of the help window by using the IHelpWindow::setTitle member function. The following code sets the title from a string defined in the resource file:

       helpWindow.setTitle(STR_HTITLE);

5. Create a help handler by creating an IHelpHandler derived class.

   A help handler processes help events. Create your own help handler class derived from IHelpHandler to provide help event processing that is unique to your application. Hello World version 5 uses a help handler only to display the keys help panel describing accelerator key definitions.

   To override keys help processing, do the following:

   1. Define a new class that is derived from IHelpHandler, as shown in the Hello World version 5 class definition file, ahellow5.hpp.

          class AHelpHandler : public IHelpHandler
          {
            public:

          /*------------------------------ Destructor ------------------------------|
          | Destruct the object with:                                               |
          | 1) No parameters                                                        |
          -------------------------------------------------------------------------*/
              virtual ~AHelpHandler() { }

            protected:
          /*----------------------- Override keysHelpId Function -------------------|
          | The keysHelpId() function is called to set the event result to the      |
          |   ID within the Hello World help libraries for Keys Help.               |
          |------------------------------------------------------------------------*/
          virtual bool
               keysHelpId(IEvent& evt);
          };

   2. Provide the overridden virtual function keysHelpId, which is called when keys help is requested. The following code, from the Hello World version 5 ahellow5.cpp file, shows how to implement this function.

          bool AHelpHandler :: keysHelpId(IEvent& evt)
          {
            evt.setResult(1000);                  //1000=keys help ID in
                                                  //  ahellow5.ipf file

            return (true);                        //Event is always processed
          } /* end AHelpHandler :: keysHelpId(...) */

      In the preceding code, the help panel ID for the Hello World version 5 keys help is set in the event result.

   3. Start and stop help events processing.

      Your help handler, previously described, does not begin handling help events until you use the handleEventsFor member function. For example, the following code causes the helpHandler to begin processing help events for this frame window:

          helpHandler.handleEventsFor(this);

      Typically, you include this statement in the constructor for the frame window.

      Note that the window that handles help events must be an associated window. That is, you should identify the window as the associated window on the IHelpWindow constructor or explicitly identify the window as an associated window using the IHelpWindow::setAssociatedWindow function.

      When you want to stop handling help events, for example, when you close your frame window, use the stopHandlingEventsFor member function, as follows:

          helpHandler.stopHandlingEventsFor(this);

      You typically include this statement in the destructor for the frame window.

   4. Associate secondary frame windows with the parent window's help window.
   5. Attach the following special handler to child frame windows in your application. This handler is needed so that help processes correctly for these windows.

          class ChildFrameHelpHandler : public IHandler {
          typedef IHandler Inherited;
          /*******************************************************************************
          *  This handler enables the OS/2 Help Manager to use help tables to display    *
          *  contextual help for a child frame window (one whose parent window is not    *
          *  the desktop).  This handler should only be attached to child frame windows. *
          *******************************************************************************/
          public:
          virtual ChildFrameHelpHandler
           &handleEventsFor       ( IFrameWindow* frame ),
           &stopHandlingEventsFor ( IFrameWindow* frame );
          protected:
          virtual bool
            dispatchHandlerEvent  ( IEvent& evt );
          ChildFrameHelpHandler
           &setActiveWindow       ( IEvent& evt, bool active = true );
          private:
          virtual IHandler
           &handleEventsFor       ( IWindow* window  ),
           &stopHandlingEventsFor ( IWindow* window  );
          };

   6. In the .cpp file, do the following:

          bool ChildFrameHelpHandler :: dispatchHandlerEvent ( IEvent& evt )
          {
            switch ( evt.eventId() )
            {
               case WM_ACTIVATE:
                  setActiveWindow(evt, evt.parameter1().number1());
                  break;
               case WM_HELP:
                  setActiveWindow(evt, true);
                  break;
               default:
                  break;
            } /* endswitch */

            return false;                     // Never stop processing of event
          }

          ChildFrameHelpHandler&
            ChildFrameHelpHandler :: setActiveWindow ( IEvent& evt,
                                                       bool active )
          {
            IHelpWindow* help = IHelpWindow::helpWindow(evt.window());
            if (help)
            {
               IFrameWindow* frame = 0;
               if (active)
               {
                  frame = (IFrameWindow*)evt.window();
               }
               help->setActiveWindow(frame, frame);
            }
            return *this;
          }

          ChildFrameHelpHandler&
            ChildFrameHelpHandler :: handleEventsFor ( IFrameWindow* frame )
          {
            IASSERTPARM(frame != 0);
            Inherited::handleEventsFor(frame);
            return *this;
          }

          ChildFrameHelpHandler&
            ChildFrameHelpHandler :: stopHandlingEventsFor ( IFrameWindow* frame )
          {
            IASSERTPARM(frame != 0);
            Inherited::stopHandlingEventsFor(frame);
            return *this;
          }

          IHandler& ChildFrameHelpHandler :: handleEventsFor ( IWindow* window  )
          {           // private to hide version in IHandler
            ITHROWLIBRARYERROR(IC_MEMBER_ACCESS_ERROR,
                               IErrorInfo::invalidRequest,
                               IException::recoverable);
            return *this;
          }

          IHandler& ChildFrameHelpHandler :: stopHandlingEventsFor ( IWindow* window  )
          {           // private to hide version in IHandler
            ITHROWLIBRARYERROR(IC_MEMBER_ACCESS_ERROR,
                               IErrorInfo::invalidRequest,
                               IException::recoverable);
            return *this;
          }

#### Assigning Help IDs to Windows

You can assign helpIDs directly to windows by using `IWindow::setHelpId( unsigned long topicId );` while maintaining portability. When F1 is pressed, the window with focus is then be queried for its context helpID and if one is found, it is used to identify the help panel to display. If one is not found and there is a help table, it is searched for the appropriate helpID to use.

If you are not using a help table, the helpId of the active frame is used as the general help panel.

#### Using Native Windows Help Files with IHelpWindow

By default, IHelpWindow uses the native help for the platform to handle help requests using a .hlp file that was created from RTF or IPF source. This allows the code you write to be portable while giving your users native look-and-feel. IPF help files are also portable between the various platforms. RTF help files are not portable. In addition, some functions provided by IPF are not available when using Windows native help (RTF). The major differences are as follows:

- There is only one instance of Windows Help for all your applications.
- The size and position of WinHelp is NOT relative to any pariticular application.
- IPF uses a set of filenames to locate help; WinHelp is one file at a time, but you must still use IHelpWindow::addLibraries to change the help file name.
- IPF help has sections for CONTENTS, INDEX, KEYS, GENERAL, and USING. WinHelp has HELP_FINDER and HELPONHELP.
- Only IPF allows the application to change the Help Manager menu and accelerators.
- Only IPF allows the application to set a title for each help object.
- Only IPF allows querying of handles for IPF sections, such as the coverpage or contents.
- Only IPF allows the application to toggle showing of the help IDs in the help manager window titles.

Refer to the Open Class Library Reference for more information on IHelpWindow and IHelpHandler.

#### Adding Fly-Over Help

Fly-over help displays short help windows for the object that the mouse pointer is currently positioned over. As users move their mouse pointer over various objects, different help windows are displayed. In addition, you can display descriptive text for the object in a text control, such as the information area at the bottom of the window.

You can use the following classes to add fly-over help to your applications:

IFlyText
  Use this static text control to display brief informative messages for a window, such as the function of a push button contained in a toolbar.
ITextControl
  Use a class derived from this base class to display longer, more detailed text. Typically, you use an information area as the ITextControl.
IFlyOverHelpHandler
  Attach an IFlyOverHelpHandler to a window to provide context-specific help messages for any window that is a child of the window you attached the handler to.

The following figure shows an example of fly-over help used on a toolbar.

#### Displaying Fly-Over Help Information

The IFlyText control displays help messages in a bordered window that is sized large enough to contain the help text. The text is displayed using one row that does not reflow. The default font used to display the help messages in PM is 8-point Helvetica.

The IFlyText control positions itself relative to one of the corners of the window the mouse pointer is over. Fly-over help displays the help message so that none of the text is drawn outside the desktop. This determines the corner of the IFlyText control from which it is drawn. The order in which the IFlyText control attempts to position itself is as follows:

1. Lower-right corner
2. Lower-left corner
3. Upper-left corner
4. Upper-right corner

You can construct instances of this class from a given window ID and an owner window.

For example:

    IFrameWindow        frameWindow( 0x1000 );
    IToolBar            toolbar( 0x1001, &frameWindow, &frameWindow );
    IFlyText            flyText( 0x1002, &toolbar );
    IFlyOverHelpHandler flyOverHelpHandler( &flyText );

    flyOverHelpHandler.handleEventsFor( &toolbar );

IFlyText provides the function setText to set the accessible attributes of each instance, and it provides functions setRelativeWindowRect and relativeWindowRect to set and query the position relative to the IFlyText control.

For Windows, the actual owner of the control is set to the first IFrameWindow object found in the owner chain of the specified owner. This insures proper operation in cases where the parentage of the specified owner is changed. For example, this occurs when you make a toolbar a floating toolbar.

The control ID of IFlyText is ignored.

#### Attaching Handlers to Provide Context-Sensitive Help

By attaching an IFlyOverHelpHandler to a window, you can provide context-specific help messages for any window that is a child of the window you attached the handler to.

You can use the IFlyOverHelpHandler to update an IFlyText control, an ITextControl, or both. The IFlyText control contains short messages (one or two words, for example) for a window, and ITextControl displays more descriptive text in the information area. You do not need a string associated with every window in your application. When a help string cannot be found for a window, a single blank is displayed by default to keep the frame extension handler from hiding the ITextControl when it contains a null string. You can also use the setMissingText function to set the text to be displayed when an information string cannot be found.

Note: | New-line characters are removed from a string before they are displayed in the IFlyText control.

The last two parameters of each handler constructor are time delays expressed in milliseconds. The first delay, indicates the time the mouse pointer must remain in in the same location before the fly-over help is displayed for the first time. The second delay, indicates the time the mouse pointer must remain in the same location after the fly-over help has been displayed for the first time.

You can change the length of the first delay using the setInitialDelayTime member function or query what is currently set using the initialDelayTime member function. Use the setDelayTime member function to change the second delay and use delayTime to query what is currently set for that second delay.

You associate context-specific help for a window to a help message by specifying a window identifier. This identifier is used with an offset to load strings from a string table. Specify different offsets into the string table for the IFlyText and the ITextControl objects to display different help messages in each of the controls.

Note: | To display help for a window using the string, you must either create the window using the Open Class Library or wrapper an existing window.

#### Dynamically Adding Help Text to Windows

You can also dynamically associate help text to a window using IFlyOverHelpHandler, a window handler. This is useful when you dynamically add controls to a canvas or push buttons to a tool bar.

Use the following functions to dynamically add or remove the help text specified for a window:

flyHelpText
  Returns the short help text for a window if you have dynamically added help text for the window.
longHelpText
  Returns the long help text for a window if you have dynamically added long help text for the window.
setHelpText
  Sets help text for a window by specifying a string or resouce ID. If you add help text to a window by the setHelpText functions, this text takes precedence over text that would otherwise be loaded from a string table.
removeHelpText
  Removes help text you added to a window through the setHelpText function.

For more information on these functions, see the Open Class Library Reference or refer to the toolbar samples in the `\samples\ioc\tbar1` and `\samples\ioc\tbar2` directory. These samples show you how to incorporate fly-over help into your applications.

Windows

Adding Menus to your Application
Adding a Menu Bar
Adding Events and Event Handlers

IFlyText
IFlyOverHelpHandler
IHelp
IHelpHandler