Building a Simple Editor Part 1

From EDM2
Jump to: navigation, search

Written by Gordon Zeglinski

Introduction

The Open Class Library (IOCL) that ships with VisualAge C++ allows the programmer to quickly develop applications. "Fancy" features such as Linkbars, fly-over help, etc. can easily be added to applications. In this issue, we revisit the simple editor created several issues ago, and add some bells and whistles to it.

Linkbars, Linkbars, Everywhere Linkbars

Just about every application has a Linkbar. Creating one without some pre-existing Linkbar control can be a daunting task. Fortunately adding a Linkbar to an IOCL based application is a snap. The ILinkbar class is an easy way to add Linkbars to your applications.

Often, this class will be inherited by the application specific Linkbar as follows:

    class EditLinkbarSet:public ILinkbar{
 
    public:
      EditLinkbarSet(IFrameWindow *wnd);
      ~EditLinkbarSet();
 
    protected:
 
      //define items that appear on Linkbar here
      ILinkbarButton       bLoad,
                           bSave;
    };

Additionally, the IOCL provides a specialized button class for use in Linkbars. This button class allows Linkbars to display text only, bitmap only or text and bitmap buttons. Linkbars can contain controls other than buttons. But for this example, we will only add in two buttons. The constructor for the EditLinkbarSet is shown below.

    EditLinkbarSet::EditLinkbarSet(IFrameWindow *wnd):
                  ILinkbar(
                     1111,                       //Linkbar ID
                     wnd,                        //frame to attach to
                     aboveClient,                //position above client & below menu
                     false,                      //don't group with other Linkbars
                     defaultStyle()              //use the default style
                  ),
                  bLoad(
                     MenLoad,                    //same ID as for the menu item load
                     this,                       //Linkbar is parent & owner of this
                     this,                            // button
                     IRectangle(),               //initial position
                     ILinkbarButton::defaultStyle()   //use default style
                  ),
                  bSave(
                     MenSave,                    //same ID as for the menu item save
                     this,
                     this,
                     IRectangle(),
                     ILinkbarButton::defaultStyle()
                  )
    {
      bLoad.setBitmap(IC_ID_OPEN);         //set the bitmap to standard open bitmap
      bLoad.setText("Open");               //set the text to Open
 
      bSave.setBitmap(IC_ID_SAVE);         //set the bitmap to standard save bitmap
      bSave.setText("Save");               //set the text to Save
 
      addAsLast(&bLoad);                   //add the buttons
      addAsLast(&bSave);                   //-----
   }

That's all there is to creating a Linkbar! There's a few things to note though. By default, all ILinkbarButtons use the standard style. This means that they all have the same appearance. Displaying long text in a standard button is impossible. To remove the standard style by changing the button style to ILinkbarButton::defaultStyle()&~ILinkbarButton::standardFormat.

To add the Linkbar to the editor window, we have to make the following changes. First, we must add a data member to the Editor class to store the instance pointer to the Linkbar.

    class Editor:public ICommandHandler{
 
    public:
      Editor();
      ~Editor();
 
 
    protected:
      Boolean        command(ICommandEvent &event);
 
      IFrameWindow   *frame;
      IMultiLineEdit *editwin;
      IString        FileName;
 
      EditLinkbarSet *Linkbar;
    };

Then we must add code to constructor and destructor to create and destroy the Linkbar. The changes are shown below.

    Editor::Editor(){
      frame=new IFrameWindow(1,  IFrameWindow::titleBar|
                                 IFrameWindow::sizingBorder|
                                 IFrameWindow::minimizeButton|
                                 IFrameWindow::maximizeButton|
                                 IFrameWindow::windowList|
                                 IFrameWindow::menuBar|
                                 IFrameWindow::systemMenu);
 
      handleEventsFor(frame);
 
      editwin=new IMultiLineEdit(10,frame,frame);
 
      frame->setClient(editwin);
      Linkbar=new EditLinkbarSet(frame);      //create the Linkbar
      frame->show();
    }
 
    Editor::~Editor(){
      delete editwin;
      delete Linkbar;                         //destroy the Linkbar
      delete frame;
    }

Help Me: Fly-over Help and Other Fun Stuff

Now that we have a working Linkbar, users usually expect fly-over help and/or a status area to tell them what the buttons do. Adding these features is a simple task. Because these features are related to the Linkbar, I'll add support for them to the EditLinkbarSet class. The new class definition follows

    class EditLinkbarSet:public ILinkbar{
 
    public:
      EditLinkbarSet(IFrameWindow *wnd);
      ~EditLinkbarSet();
 
    protected:
      IInfoArea            area;
 
      ILinkbarButton       bLoad,
                           bSave;
 
      IFlyText             flytext;
      IFlyOverHelpHandler  flyHand;
    };

Note the order in which the data members are declared.

I've noticed that the order in which the data members are declared matched the order in which they are initialized in the constructor. The initialization order specified in the constructor is NOT followed. This will affect the TAB order of controls in canvas controls in addition to data members that use other data members in their initialization code.

The new constructor for EditLinkbarSet follows.

    EditLinkbarSet::EditLinkbarSet(IFrameWindow *wnd):
                  ILinkbar(
                     1111,
                     wnd,
                     aboveClient,
                     false,
                     defaultStyle()
                  ),
                  area(          //add an info area to the bottum of the frame
                     wnd,
                     1112
                  ),
                  bLoad(
                     MenLoad,
                     this,
                     this,
                     IRectangle(),
                     ILinkbarButton::defaultStyle()
                  ),
                  bSave(
                     MenSave,
                     this,
                     this,
                     IRectangle(),
                     ILinkbarButton::defaultStyle()
                  ),
                  flytext(    //create the fly over text window
                     1113,
                     this
                  ),
                  flyHand(       //create the help handler
                     &flytext,   //put fly over help in here
                     &area       //put the long descriptions in the infoarea
                  )
    {
      bLoad.setBitmap(IC_ID_OPEN);
      bLoad.setText("Open");
 
      bSave.setBitmap(IC_ID_SAVE);
      bSave.setText("Save");
 
      addAsLast(&bLoad);
      addAsLast(&bSave);
 
      //set the bases in the string table
      flyHand.setFlyTextStringTableOffset( FlyBase );
      flyHand.setLongStringTableOffset( LongBase );
      //start handling flyover for the Linkbar
      flyHand.handleEventsFor(this);
    }

The fly-over help handler loads string from the string resource table. The string it loads for a particular control is based on the control's ID number and the particular table offset (see the included .rc file for an example). It is possible to have a short text phrase for the fly-over window and a longer, more descriptive phrase for the status area.

Once the appropriate entries are added to the string table in the .rc file, and the new code is compiled, we have working fly-over help. All the source for both NT and OS/2 VAC++ is included in oops_src.zip.

Wrapping Things Up

We've seen that adding a Linkbar, fly-over help and an info-area to an application is easy using the IOCL. Although there's a few tricks that have to be looked out for, they are not a hinderance to quickly adding these nifty features to an application.