Jump to content

The V C++ GUI Framework User Guide:Tutorial:Tutorial code

From EDM2
Revision as of 04:24, 12 November 2012 by Martini (talk | contribs) (Created page with " Tutorial C++ Source The following is a complete tutorial V application. The source for this tutorial is available int the directory ~/v/tutor. The Application tutapp.cpp //===...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Tutorial C++ Source The following is a complete tutorial V application. The source for this tutorial is available int the directory ~/v/tutor.

The Application tutapp.cpp

//======================================================================== // tutapp.cpp: Source file for tutorial V application // // Copyright 1995, Bruce E. Wampler. All rights reserved. //======================================================================== // // This file is used to define the main application object. There // will be exactly one instance of the application object. You will // usually derive you own app class from the vApp class. This file // defines a sample tutApp class. The usual purpose of tutApp is to // start the initial window, and act as a central controller for // your application. Rather than reading this file sequentially, // you should skip to the end and read the comments surrounding the // AppMain function.


// Files required for tutorial minimal application: // tutapp.h: Header for the min app // tutapp.cpp: Source code for min app // tcmdwin.h: Header code for sample command window // tcmdwin.cpp: Source code for sample command window // tdialog.h: Header for sample modeless dialog // tdialog.cpp: Source for sample modeless dialog // tmodal.h: Header for sample modal dialog // tmodal.cpp: Source for sample modal dialog //

// First #include header files we need to use.

  1. include "tutapp.h" // our header file

//=========================>>> tutApp::NewAppWin <<<======================

 vWindow* tutApp::NewAppWin(vWindow* win, char* name, int w, int h,
   vAppWinInfo* winInfo)
 {
   // This version of NewAppWin is provided with the information
   // required to name and size a window.
   // 
   // Typically, this method would get a file name or other information
   // needed to setup the AppWinInfo class  specifically for the
   // application. Thus, each open window usually represents a view of
   // a file or data object.
   vWindow* thisWin = win;             // local copy to use
   vAppWinInfo* awinfo = winInfo;
   char *myname = name;                // local copy
   if (!*name)
       myname = "Example";            // make up a name
       
   // The UserDebug macros are useful for tracking what is going on.
   // This shows we're building a window.
   UserDebug1(Build,"tutApp::NewAppWin(%s)\n",myname);
   // You may instantiate an instance of the window outside of
   // NewAppWin, or allow NewAppWin to create the instance.
   if (!thisWin)       // Didn't provide a window, so create one.
       thisWin = new tCmdWindow(myname, w, h);
   // The vAppWinInfo class is meant to serve as a database used by the
   // tutApp controller. If you use this feature, you will probably
   // derive your own myAppWinInfo class from vAppWinInfo. The instance
   // of vAppWinInfo created here will be automatically deleted when
   // this window instance is closed through CloseAppWin.
   if (!awinfo)        // Did caller provide an appinfo?
       awinfo = new vAppWinInfo(myname);
   // After you have created an instance of the window and an instance
   // of the AppWinInfo, you MUST call the base vApp::NewAppWin method.
   // You won't need to explicitly keep track of the pointer to
   // each new window -- unless it has to interact with other windows.
   // If that is the case, then you can use your derived vAppWinInfo
   // to coordinate the interaction.
   return vApp::NewAppWin(thisWin,name,w,h,awinfo);
 }

//===========================>>> tutApp::Exit <<<=========================

 void tutApp::Exit(void)
 {
   // This can be called to close all windows. If the app needs to do
   // something special, it can. Otherwise, it can call the general
   // vApp::Exit method, which will perform appropriate calls the the
   // specialized tutApp::CloseAppWin.
   UserDebug(Build,"tutApp::Exit()\n");
   vApp::Exit();       // easy default behavior
 }

//======================>>> tutApp::CloseAppWin <<<=======================

 void tutApp::CloseAppWin(vWindow* win)
 {
   // This will be called BEFORE a window has been unregistered or
   // closed. The app can do whatever it needs to to close down the
   // data associated with this window. (It is invoked explicitly by
   // you in response to a Close menu pick, for example, or when the
   // user clicks the close button. It can also be called by vApp::Exit().
   // After this method cleans up, it can then call the superclass
   // vApp::CloseAppWin to unregister and close this window. Note that
   // the win gives a handle that can be used with vApp::getAppWinInfo
   // to retrieve the AppWinInfo class.
   UserDebug(Build,"tutApp::CloseAppWin()\n");
   // Code to handle close of window (such as saving/closing
   // a file) would go here...
   vApp::CloseAppWin(win);   // Unregister and close the window.
 }

//=====================>>> tutApp::AppCommand <<<=========================

 void tutApp::AppCommand(vWindow* win, ItemVal id, ItemVal val,
   CmdType cType)
 {
   // Any commands not processed by the window WindowCommand
   // method will be passed to here for default treatment.
   UserDebug1(Build,"tutApp::AppCmd(ID: %d)\n",id);
   vApp::AppCommand(win, id, val, cType);
 }

//=======================>>> tutApp::KeyIn <<<============================

 void tutApp::KeyIn(vWindow* win, vKey key, unsigned int shift)
 {
   // Any key strokes not processed by the window will be passed
   // along to here for default treatment.
   vApp::KeyIn(win, key, shift);
 }

//======================================================================== // Remember that any static references to an object are constructed by // the C++ startup code before main or any other functions are called. // Thus, the constructor for tutApp (and thus vApp) is invoked before // anything else happens. This enables V to perform whatever // initializations are required by the host GUI system - and frees you // from having to worry about the typical gory details. All this means // that EVERY V application needs a static instance of the tutApp to // get things rolling. Note that the global variable theApp is set to // point to this instance, and is the easiest way to access the vApp // and tutApp methods (e.g., theApp->Exit()). //========================================================================

 static tutApp tut_App("TutorApp");  // The single instance of the app

//===========================>>> AppMain <<<==============================

 int AppMain(int argc, char** argv)
 {
   // The V framework defines the instance of main. After some
   // processing of command line arguments, AppMain is called with
   // cleaned up command line arguments. Note that at this time, no
   // windows have been defined. Normally, AppMain is the place to
   // start up the first window. You can perform any initialization you
   // need to do here.
   (void) theApp->NewAppWin(0, "Tutorial V Example", 350, 100, 0);
   // At this point, the window is up, and all events are being
   // routed through its methods.
   // We MUST return 0 if the status is OK at this point.
   return 0;
 }

tutapp.h

//======================================================================== // tutapp.h: Header file for tutorial V application // // Copyright 1995, Bruce E. Wampler. All rights reserved. //========================================================================

  1. ifndef TUTAPP_H // Standard technique for avoiding
  2. define TUTAPP_H // problems with multiple #includes
  1. ifdef vDEBUG
  2. include <v/vdebug.h>
  3. endif
  1. include <v/vapp.h> // We are derived from vApp
  2. include <v/vawinfo.h> // Need for app info
  1. include "tcmdwin.h" // we use our tCmdWindow class
   class tutApp : public vApp
     {
       friend int AppMain(int, char**); // allow AppMain access
     public:           //---------------------------------------- public
       tutApp(char* name) : vApp(name) {}      // just call vApp
       virtual ~tutApp() {}
       // Routines from vApp that are normally overridden
       virtual vWindow* NewAppWin(vWindow* win, char* name, int w, int h,
          vAppWinInfo* winInfo);
       virtual void Exit(void);
       virtual void CloseAppWin(vWindow* win);
       virtual void AppCommand(vWindow* win, ItemVal id,
               ItemVal val, CmdType cType);
       virtual void KeyIn(vWindow* win, vKey key,
           unsigned int shift);
       // New routines for this particular app go here
     protected:        //------------------------------------- protected
     private:          //--------------------------------------- private
     };
  1. endif

The Command Window

tcmdwin.cpp

//======================================================================== // tcmdwin.cpp: Source file for tutorial cmdwin class // // Copyright 1995, Bruce E. Wampler. All rights reserved. //========================================================================

// This file contains the source code for a typical command window // derived from the vCmdWindow class. It will contain the definitions // of the menu bar and command and status bars. It represents the main // interaction point with the user. // // We start out with the #includes needed to define this class plus // any V utility dialogs such as vNotice we use.

  1. include <v/vnotice.h> // so we can use notice
  2. include <v/vkeys.h> // to map keys
  3. include <v/vutil.h> // for utilities
  4. include <v/vfilesel.h> // for file select
  1. include "tcmdwin.h" // our header file

// Now, we define static arrays for the menus, command bars, and // status bars used by this window. This consists of defining the // constants needed for IDs, followed by the static declarations of // the menu and command arrays. Note that V predefines quite a few // standard IDs which you can use instead of defining your own.

 // Start ID defines for the main window at 100
 const ItemVal m_CheckMe = 100;  // for CheckMe command
 const ItemVal m_CopySens = 101; // for Set Copy Sensitive
 const ItemVal m_Dialog = 102;   // to pop up the dialog
 const ItemVal m_ModalDialog = 103; // for modal dialog
 const ItemVal m_Clear = 104;    // Clear screen

// Now, the static declarations of the menu arrays. You first define // the pulldown menus, one for each main menu bar label.

   static vMenu FileMenu[] =    // Items for File menu
     {
       {"New",M_New,isSens,notChk,noKeyLbl,noKey,noSub},
       {"Open",M_Open,isSens,notChk,noKeyLbl,noKey,noSub},
       {"Save",M_Save,notSens,notChk,noKeyLbl,noKey,noSub},
       {"Save As",M_SaveAs,notSens,notChk,noKeyLbl,noKey,noSub},
  1. ifdef vDEBUG // Defines V debug code
       {"-",M_Line,notSens,notChk,noKeyLbl,noKey,noSub},
       {"Debug",M_SetDebug,isSens,notChk,noKeyLbl,noKey,noSub},
  1. endif
       {"-",M_Line,notSens,notChk,noKeyLbl,noKey,noSub},
       {"Exit",M_Exit,isSens,notChk,noKeyLbl,noKey,noSub},
       {NULL}
     };
   static vMenu EditMenu[] =    // Items for Edit menu
     {
       {"Cut",M_Cut,notSens,notChk,noKeyLbl,noKey,noSub},
       {"Copy",M_Copy,notSens,notChk,noKeyLbl,noKey,noSub},
       {"Paste",M_Paste,notSens,notChk,noKeyLbl,noKey,noSub},
       {NULL}
     };
   static vMenu TestMenu[] =   // Items for Test menu
     {
       {"CheckMe",m_CheckMe,isSens,notChk,noKeyLbl,
           noKey,noSub},
       {"Copy Sensitive",m_CopySens,isSens,notChk,noKeyLbl,
           noKey,noSub},
       {"Dialog",m_Dialog,isSens,notChk,noKeyLbl,
           noKey,noSub},
       {"Modal Dialog",m_ModalDialog,isSens,notChk,noKeyLbl,
           noKey,noSub},
       {NULL}
     };
   // Now, define the items on the menu bar
   vMenu StandardMenu[] =     // The menu bar with three items
     {
       {"File",M_File,isSens,notUsed,notUsed,noKey,&FileMenu[0]},
       {"Edit",M_Edit,isSens,notUsed,notUsed,noKey,&EditMenu[0]},
       {"Test",M_Test,isSens,notUsed,notUsed,noKey,&TestMenu[0]},
       {NULL}
     };

// We now define a command bar. Command bars are optional, and there // may be more than one. You can place any CommandObject you want on a // command bar.

   static CommandObject CommandBar[] =  // A simple command bar
     {
       {C_Label,999,0 ,"Command Bar",NoList,CA_None,
           isSens,NoFrame,0,0},
       {C_Button,M_Copy,M_Copy,"Copy",NoList,CA_None,
           notSens,NoFrame,0,0},
       {C_Button,m_Dialog,m_Dialog,"Dialog",NoList,CA_None,
           isSens,NoFrame,0,0},
       {C_Button,m_Clear,m_Clear,"Clear",NoList,CA_None,
           isSens,NoFrame,0,0},
       {C_Button,M_Exit,M_Exit,"Exit",NoList,CA_None,
           isSens,NoFrame,0,0},
       {C_EndOfList,0,0,0,0,CA_None,0,0,0}  // This ends list
     };

// Sometimes it is easier to define IDs near the definition of // the dialog or status bar using them.

 const ItemVal m_cmdMsg = 110;
 const ItemVal m_cmdCount = 111;
 const ItemVal m_keyMsg = 112;
 const ItemVal m_keyVal = 113;
   static vStatus StatBar[] =    // Define a simple status bar
     {
       {"Commands issued: ",m_cmdMsg,CA_NoBorder,isSens,0},
       {" ",m_cmdCount,CA_None,isSens,0},
       {"Last keypress: ",m_keyMsg,CA_NoBorder,isSens,0},
       {"   ",m_keyVal,CA_None,isSens,0},
       {0,0,0,0,0}           // This ends list
     };
   static int copy_sens = 0;   // local for tracking sensitive

//======================>>> tCmdWindow::tCmdWindow <<<====================

 tCmdWindow::tCmdWindow(char* name, int width, int height) :
   vCmdWindow(name, width)
 {
   // This is the constructor for tCmdWindow. 
   
   UserDebug1(Constructor,"tCmdWindow::tCmdWindow(%s) Constructor\n",name)
   // The "Standard" window will consist of a menubar, a canvas, an
   // optional button bar, and an optional status bar.
   // 
   // First, create and add the proper panes to the CmdWindow
   // Note: there must be a corresponding delete in the destructor
   // Create and add the standard Menu Bar to this window
   myMenu = new vMenuPane(StandardMenu);
   AddPane(myMenu);
   // Create and add our Canvas pane to this window
   myCanvas = new tCanvasPane;
   AddPane(myCanvas);
   // Create and add the command pane to this window
   myCmdPane = new vCommandPane(CommandBar);
   AddPane(myCmdPane);
   // Create and add the Status Bar to this window
   myStatus = new vStatusPane(StatBar);
   AddPane(myStatus);
   // In the V model, a window may have dialogs. Each dialog used
   // by a window must have an instance pointer. The easiest way
   // to create dialogs is to construct each one using a new here
   // which only defines the dialog - you need to use its
   // ShowDialog method at the appropriate time to display it).
   // You delete dialogs in the destructor for this window.
   // 
   // Now, create whatever dialogs this app defines:
   // instances of tDialog and tModalDialog
   sampleDialog = new tDialog(this);
   sampleModalDialog = new tModalDialog(this);
   // FINALLY, after all the panes have been constructed and
   // added, we must show the window!
   ShowWindow();
 }

//=====================>>> tCmdWindow::~tCmdWindow <<<====================

 tCmdWindow::~tCmdWindow()
 {
   UserDebug(Destructor,"tCmdWindow::~tCmdWindow() destructor\n")
   // Now put a delete for each new in the constructor.
   delete myMenu;
   delete myCanvas;
   delete myStatus;
   delete myCmdPane;
   delete sampleDialog;
   delete sampleModalDialog;
 }

//========================>>> tCmdWindow::KeyIn <<<=======================

 void tCmdWindow::KeyIn(vKey keysym, unsigned int shift)
 {
   // Keystrokes are routed to this window. This example code shows very
   // simple processing of keystrokes, and how to update the m_keyVal
   // field of the status bar.
   static char ctrl[] = "^X ";
   static char chr[] = " X ";
   if (VK_IsModifier(keysym))
       SetString(m_keyVal, "mod");     // change status bar
   else if (keysym < ' ')              // ctrl char
     {
       ctrl[1] = keysym + '@';
       SetString(m_keyVal, ctrl);      // change status bar
     }
   else if (keysym < 128)              // normal printable char
     {
       chr[1] = keysym;
       SetString(m_keyVal, chr);       // change status bar
     }
   else 
       SetString(m_keyVal, "+++");     // change status bar
 }

//====================>>> tCmdWindow::WindowCommand <<<===================

 void tCmdWindow::WindowCommand(ItemVal id, ItemVal val, CmdType cType)
 {
   // All commands generated from this window's menus and dialog bars
   // are routed through here.  The easiest way to handle commands is to
   // use a single, sometimes large switch. Each time you add a command
   // to a menu or command bar, add a case to the switch here. In this
   // example, we use the V Notice dialog to display entered commands.
   static int cmdCount = 0;    // Used for sample status update
   vNoticeDialog note(this);   // Used for default actions
   char buff[20];              // buffer for status bar
   ++cmdCount;                 // count commands that have been issued
   IntToStr(cmdCount,buff);    // Use V utility routine to get string
   SetString(m_cmdCount, buff);        // change status bar
   UserDebug1(CmdEvents,"tCmdWindow:WindowCommand(%d)\n",id)
   switch (id)                 // The main switch to handle commands
     {
       // File Menu commands ------------------------------------
       case M_New:             // For this example, we will open a
         {                     // new window using our NewAppWin.
           (void) theApp->NewAppWin(0,"",250,100);
           break;
         }
       case M_Open:            // This demos vFileSelect dialog
         {
           char name[100] = "";        // start out with null name
           vFileSelect fsel(this);     // an instance of vFileSelect
           int fI;                     // Filter index
           static char* filter[] = {   // Filter for file select
               "*", "*.txt", "*.c *.cpp *.h", 0 };
           // Show the file select dialog
           int ans = fsel.FileSelect("Open file",name,99,filter,fI);
           if (ans && *name)   // User picked a file name
             {
               SetTitle(name); // Set title of window to name
               note.Notice(name);  // Show the name
             }
           else                // Notify no name selected
               note.Notice("No file name selected.");
         }
       case M_Save:            // This would usually save a file
         {
           note.Notice("Save");
           break;
         }
       case M_SaveAs:          // Save to a specified name
         {
           note.Notice("Save As");
           break;
         }
  1. ifdef vDEBUG // Include debugging like this
       case M_SetDebug:
         {
           vDebugDialog debug(this);   // an instance of debug 
           debug.SetDebug();           // dialog - let user set
           break;
         }
  1. endif
       case M_Exit:            // Standard exit command
         {                     // Invoke the standard app Exit
           theApp->Exit();     // to close all windows
           break;              // will never get here
         }
       // Edit Menu commands ------------------------------------
       case M_Cut:             // Standard items for Edit menu
         {
           note.Notice("Cut");
           break;
         }
       case M_Copy:
         {
           note.Notice("Copy");
           break;
         }
       case M_Paste:
         {
           note.Notice("Paste");
           break;
         }
       // Test Menu commands ------------------------------------
       case m_CheckMe:         // Demonstrate using a checked menu
         {
           ItemVal curval = GetValue(id); // Get current status
           SetValue(m_CheckMe,!curval,Checked); // Toggle check
           if (curval)                 // Change menu label
               SetString(m_CheckMe,"Check Me");
           else
               SetString(m_CheckMe,"UnChk Me");
           break;
         }
       case m_CopySens:        // Demo changing sensitivity
         {
           copy_sens = !copy_sens;     // toggle
           // This will change both menu and command button
           SetValue(M_Copy,copy_sens,Sensitive);
           break;
         }
       case m_Dialog:          // Invoke our dialog
         {
           if (!sampleDialog->IsDisplayed())   // not twice!
               sampleDialog->ShowDialog("Sample Modeless Dialog");
           break;
         }
       case m_ModalDialog:     // Invoke our modal dialog
         {
           ItemVal val, id;
           id = sampleModalDialog->ShowModalDialog("Sample Modal",val);
           // Now do something useful with id and val ...
           break;
         }
       case m_Clear:           // Clear the canvas
         {
           myCanvas->Clear();  // Invoke the canvas Clear
           break;
         }
       default:                // route unhandled commands up
         {                     // to superclass
           vCmdWindow::WindowCommand(id, val, cType);
           break;
         }
     }
 }

tcmdwin.h

//======================================================================== // tcmdwin.h: Header file for tutorial V command window // // Copyright 1995, Bruce E. Wampler. All rights reserved. //======================================================================== // // Derive a window from the vCmdWindow class

  1. ifndef TCMDWIN_H
  2. define TCMDWIN_H
  1. include <v/vcmdwin.h> // So we can use vCmdWindow
  2. include <v/vmenu.h> // For the menu pane
  3. include <v/vstatusp.h> // For the status pane
  4. include <v/vcmdpane.h> // command pane
  1. ifdef vDEBUG
  2. include <v/vdebug.h>
  3. endif
  1. include "tdialog.h" // user defined: tDialog
  2. include "tmodal.h" // user defined: tModalDialog
  3. include "tcanvas.h" // user defined: tCanvasPane
   class tCmdWindow : public vCmdWindow
     {
       friend int AppMain(int, char**);        // allow AppMain access
     public:           //---------------------------------------- public
       tCmdWindow(char*, int, int);    // Constructor with size
       virtual ~tCmdWindow();          // Destructor
       virtual void WindowCommand(ItemVal id,ItemVal val,CmdType cType);
       virtual void KeyIn(vKey keysym, unsigned int shift);
     protected:        //------------------------------------- protected
     private:          //--------------------------------------- private
       // Each user CmdWindow should conform to a "Standard" window,
       // which includes a menu bar, a canvas, an optional command bar,
       // and an optional status bar.
       vMenuPane* myMenu;              // For the menu bar
       tCanvasPane* myCanvas;          // For the canvas
       vStatusPane* myStatus;          // For the status bar
       vCommandPane* myCmdPane;        // for the command pane
       // Each user CmdWindow will probably have some dialogs and
       // subwindows. Declare pointers to each instance here.
       tDialog* sampleDialog;
       tModalDialog* sampleModalDialog;
     };
  1. endif

The Canvas

tcanvas.cpp

//======================================================================== // tcanvas.cpp - source for tutorial canvas // // Copyright 1995, Bruce E. Wampler, All Rights Reserved. //======================================================================== // // Each V application usually needs a canvas. In order to handle // various events: mouse, redraw, resize, and scroll, you will need to // derive your own canvas class. The base V vCanvasPane class can only // draw -- it does not have any memory of what has been drawn on the // screen (the vTextCanvasPane does handle redrawing, but is still // limited). Thus, your class will usually be responsible for handling // redrawing. This example is very simple. It lets the user draw // lines - up to 200 - and will redraw the screen when it has been // exposed.

// The example does not handle scrolling.

  1. include "tcanvas.h" // include our header file

//====================>>> tCanvasPane::tCanvasPane <<<====================

 tCanvasPane::tCanvasPane()
 {
   // The constructor initializes our simple data structure.
   _mouseDown = 0; _nextpt = 0;
   _begx = -1; _begy = -1; _curx = -1; _cury = -1;
   _pt = new point[200];       // allocate only 200 lines
 }

//-===================>>> tCanvasPane::tCanvasPane <<<====================

 tCanvasPane::~tCanvasPane()
 {
   delete [] _pt;              // free the point array
 }

//======================>>> tCanvasPane::Clear <<<========================

 void tCanvasPane::Clear()
 {
   vCanvasPane::Clear();       // clear the canvas
   _nextpt = 0;                // start over at 0
 }

// This example does not handle scrolling, but a derived canvas would // be likely to. Thus, we've included the derived scrolling methods, // but simply call the superclass method for default handling, which // is essentially a no op.

//======================>>> tCanvasPane::HPage <<<========================

 void tCanvasPane::HPage(int shown, int top)
 {
   vCanvasPane::HPage(shown, top);
 }

//======================>>> tCanvasPane::VPage <<<========================

 void tCanvasPane::VPage(int shown, int top)
 {
   vCanvasPane::VPage(shown, top);
 }

//======================>>> tCanvasPane::HScroll <<<======================

 void tCanvasPane::HScroll(int step)
 {
   vCanvasPane::HScroll(step);
 }

//======================>>> tCanvasPane::VScroll <<<======================

 void tCanvasPane::VScroll(int step)
 {
   vCanvasPane::VScroll(step);
 }

//=====================>>> tCanvasPane::MouseDown <<<=====================

 void tCanvasPane::MouseDown(int X, int Y, int button)
 {
  // Mouse down means the user is starting a line. We don't care which
  // button was pressed. There is nothing to draw until the mouse moves.
   _mouseDown = 1;                     // track mouse button
   _pt[_nextpt].x = _begx = _curx = X; // starting point
   _pt[_nextpt].y = _begy = _cury = Y;
   if (++_nextpt >= 200)               // set next point and do a simple
       _nextpt = 0;                    // minded storage allocation
 }

//======================>>> tCanvasPane::MouseMove <<<====================

 void tCanvasPane::MouseMove(int x, int y, int button)
 {
   // Mouse move means the user is drawing a line, so we have to draw
   // it on the screen. By drawing a Rubber Line, we can easily track
   // the user motions, and undraw the previous line.
   if (_begx != _curx || _begy != _cury) // Was there a previous line?
       DrawRubberLine(_begx, _begy, _curx, _cury);  // Undraw old line
   if (_begx != x || _begy != y)       // If we moved, draw new line
       DrawRubberLine(_begx, _begy, x, y);
   
   _curx = x; _cury = y;               // update positions
 }

//========================>>> tCanvasPane::MouseUp <<<====================

 void tCanvasPane::MouseUp(int X, int Y, int button)
 {
   // Mouse up means the user has ended a line, so we need to draw
   // a permanent line and update the data base.
   _mouseDown = 0;                     // Mouse down now
   if (_begx != X || _begy != Y)       // We drew a line
       DrawLine(_begx, _begy, X, Y);   // So draw permanent version
   _pt[_nextpt].x = X; _pt[_nextpt].y = Y;  // End point
   if (++_nextpt >= 200)               // set next point and do a simple
       _nextpt = 0;                    // minded storage allocation
   _begx = -1; _begy = -1; _curx = -1; _cury = -1;  // for next line
 }

//========================>>> tCanvasPane::Redraw <<<=====================

 void tCanvasPane::Redraw(int x, int y, int w, int h)
 {
   // This is a simple Redraw that just redraws everything.
   // Often, that will be more than fast enough, but the input
   // parameters can be used to make a more intelligent redraw.
   for (int i = 0 ; i < _nextpt ; i += 2)
       DrawLine(_pt[i].x, _pt[i].y, _pt[i+1].x, _pt[i+1].y);
 }

//======================>>> tCanvasPane::Resize <<<=======================

 void tCanvasPane::Resize(int w, int h)
 {
   // We also don't handle resizing in this example.
   vCanvasPane::Resize(w,h);
 }

tcanvas.h

//======================================================================== // tcanvas.h -- header file for tutorial canvas class // // Copyright 1995, Bruce E. Wampler, All Rights Reserved. //========================================================================

  1. ifndef TCANVAS_H
  2. define TCANVAS_H
  1. include <v/vcanvas.h> // derive from vCanvasPane
   typedef struct point        // simple structure for points
     {
       int x; int y;
     } point;
   class tCanvasPane : public vCanvasPane
     {
     public:           //---------------------------------------- public
       tCanvasPane();
       virtual ~tCanvasPane();
       // Windows
       virtual void Clear();
       // Scrolling
       virtual void HPage(int, int);
       virtual void VPage(int, int);
       virtual void HScroll(int);
       virtual void VScroll(int);
       // Events
       virtual void MouseDown(int, int, int);
       virtual void MouseUp(int, int, int);
       virtual void MouseMove(int, int, int);
       virtual void Redraw(int, int, int, int); // Expose/redraw event
       virtual void Resize(int, int);          // Resize event
     protected:        //------------------------------------- protected
     private:          //--------------------------------------- private
       // Note that we try to use a leading underscore to indicate
       // private members. We aren't always consistent!
       int _mouseDown;         // track if mouse down
       int _begx; int _begy;   // starting point
       int _curx; int _cury;   // current point
       point *_pt;             // the array of points
       int _nextpt;            // where next point goes
     };
  1. endif

A.4 A Modeless Dialog

tdialog.cpp

//========================================================================
//  tdialog.cpp - Source file for tutorial tDialog class
//
//  Copyright 1995, Bruce E. Wampler, All Rights Reserved
//========================================================================

// #include the headers we need
#include <v/vnotice.h>
#include "tdialog.h"

// The structure of a derived dialog class is very similar to the
// structure of a command window class. First we define IDs for the
// various command objects used in the dialog. Then we declare the
// static array that defines the dialog.

const ItemVal mdLbl1 = 200;

const ItemVal mdFrm1 = 201;  const ItemVal mdLbl2 = 202;
const ItemVal mdCB1 = 203;   const ItemVal mdCB2 = 204;
const ItemVal mdCB3 = 205;

const ItemVal mdFrmV1 = 206; const ItemVal mdLbl3 = 207;
const ItemVal mdRB1 = 208;   const ItemVal mdRB2 = 209;

const ItemVal mdFrmV2 = 210; const ItemVal mdLbl4 = 211;
const ItemVal mdBtn1 = 212;  const ItemVal mdBtn2 = 213;

const ItemVal mdBtnChange = 214;

    static char change_me[] = "Change Me A";    // a label to change

// This defines the dialog

    static CommandObject DefaultCmds[] =
      {
        {C_Label, mdLbl1, 0,"X",NoList,CA_MainMsg,isSens,NoFrame, 0, 0},

        {C_Frame,mdFrmV2,0,"",NoList,CA_None,isSens,NoFrame,0,mdLbl1},
        {C_Label,mdLbl4,0,"Buttons",NoList,CA_None,isSens,mdFrmV2,0,0},
        {C_Button,mdBtn1,mdBtn1,"Button 1",NoList,CA_None,
                isSens,mdFrmV2,0,mdLbl4},
        {C_Button,mdBtn2,mdBtn2,"Button 2",NoList,CA_None,
                isSens,mdFrmV2,0,mdBtn1},

        {C_Frame,mdFrm1,0,"",NoList,CA_None,isSens,NoFrame,mdFrmV2,mdLbl1},
        {C_Label,mdLbl2,0,"CheckBox",NoList,CA_None,isSens,mdFrm1,0,0},
        {C_CheckBox,mdCB1,0,"Test A",NoList,CA_None,
                isSens,mdFrm1,0,mdLbl2},
        {C_CheckBox,mdCB2,0,"Test B",NoList,CA_None,
                isSens,mdFrm1,mdCB1,mdLbl2},
        {C_CheckBox,mdCB3,1,"Test C",NoList,CA_None,isSens,mdFrm1,0,mdCB1},

        {C_Frame,mdFrmV1,0,"",NoList,CA_None,isSens,NoFrame,mdFrm1,mdLbl1},
        {C_Label,mdLbl3,0,"Radios",NoList,CA_None,isSens,mdFrmV1,0,0},
        {C_RadioButton,mdRB1,1,"KOB",NoList,CA_None,
                isSens,mdFrmV1,0,mdLbl3},
        {C_RadioButton,mdRB2,0,"KOAT",NoList,CA_None,
                isSens,mdFrmV1,0,mdRB1},

        {C_Button,mdBtnChange,0,change_me,NoList,CA_None,
                isSens,NoFrame,0,mdFrmV1},
        {C_Button,M_Cancel,M_Cancel," Cancel ",NoList,CA_None,
            isSens,NoFrame,mdBtnChange,mdFrmV1},
        {C_Button,M_OK,M_OK," OK ",NoList,CA_DefaultButton,
            isSens,NoFrame,M_Cancel,mdFrmV1},

        {C_EndOfList,0,0,0,0,CA_None,0,0,0}
      };


//==========================>>> tDialog::tDialog <<<======================
  tDialog::tDialog(vBaseWindow* bw) :
    vDialog(bw)
  {
    // The constructor for a derived dialog calls the superclass
    // constructor, and then adds the command objects to the dialog
    // by calling AddDialogCmds.

    UserDebug(Constructor,"tDialog::tDialog()\n")
    AddDialogCmds(DefaultCmds);         // add the command objects
  }

//=========================>>> tDialog::~tDialog <<<======================
  tDialog::~tDialog()
  {
    // Destructor often doesn't need to do anything

    UserDebug(Destructor,"tDialog::~tDialog() destructor\n")
  }

//====================>>> tDialog::DialogCommand <<<======================
  void tDialog::DialogCommand(ItemVal id, ItemVal retval, CmdType ctype)
  {
    // After the user has selected a command from the dialog,
    // this routine is called with the value.

    vNoticeDialog note(this);   // an instance we can use

    UserDebug1(CmdEvents,"tDialog::DialogCommand(id:%d)\n",id)

    switch (id)         // We will do some things depending on value
      {
        case mdCB1:             // CheckBox
            note.Notice("Test A");
            break;

        case mdCB2:             // CheckBox
            note.Notice("Test B");
            break;

        case mdCB3:             // CheckBox
            note.Notice("Test C");
            break;

        case mdRB1:             // Radio Button
            note.Notice("KOB");
            break;

        case mdRB2:             // Radio Button
            note.Notice("KOAT");
            break;

        case mdBtn1:            // Button
            note.Notice("Button 1");
            break;

        case mdBtn2:            // Button
            note.Notice("Button 2");
            break;

        case mdBtnChange:       // Example: change my own label
            // We will change the label on this button
            change_me[10]++;            // change the "A"
            SetString(mdBtnChange, change_me);
            break;
      }
    // All commands should also route through the parent handler
    // which has useful default behaviors for Cancel and OK
    vDialog::DialogCommand(id,retval,ctype);
  }

tdialog.h

//========================================================================
//
//  tdialog.h - Header file for tutorial tDialog class
//
//  Copyright 1995, Bruce E. Wampler, All Rights Reserved
//========================================================================

#ifndef TDIALOG_H
#define TDIALOG_H

#include <v/vdialog.h>  // we derive from vDialog

    class tDialog : public vDialog
      {
      public:           //---------------------------------------- public
        tDialog(vBaseWindow*);
        virtual ~tDialog();             // Destructor
        virtual void DialogCommand(ItemVal id, ItemVal retval,
                CmdType ctype);

      protected:        //------------------------------------- protected

      private:          //--------------------------------------- private
        int _toggleId;
      };
#endif

==A.5  A Modal Dialog==

tmodal.cpp
<PRE>
//========================================================================
//  tmodal.cpp - Source file for tutorial tModalDialog class
//
//  Copyright 1995, Bruce E. Wampler, All Rights Reserved
//========================================================================
//

#include "tmodal.h"             // our header file
#include <v/vnotice.h>

const ItemVal mmLbl1 = 300;
const ItemVal mmBtn1 = 301;
const ItemVal mmBtn2 = 302;

    static  DefaultCmds[] =
      {
        {C_Label, mmLbl1, 0,"X",NoList,CA_MainMsg,isSens,NoFrame, 0, 0},
        
        {C_Button,mmBtn1,mmBtn1," Test 1 ",NoList,CA_None,
                isSens,NoFrame,0,mmLbl1},
        {C_Button,mmBtn2,mmBtn2," Test 2 ",NoList,CA_None,
                isSens,NoFrame, mmBtn1,mmLbl1},

        {C_Button,M_Cancel,M_Cancel," Cancel ",NoList,CA_None,
                isSens,NoFrame, 0,mmBtn1},
        {C_Button,M_OK,M_OK,"   OK   ",NoList,CA_DefaultButton,
                isSens,NoFrame,M_Cancel,mmBtn1},

        {C_EndOfList,0,0,0,0,CA_None,0,0,0}
      };


//======================>>> tModalDialog::tModalDialog <<<================
  tModalDialog::tModalDialog(vBaseWindow* bw) :
    vModalDialog(bw)
  {
    UserDebug(Constructor,"tModalDialog::tModalDialog()\n")
    AddDialogCmds(DefaultCmds);         // add the predefined commands
  }

//=================>>> tModalDialog::~tModalDialog <<<====================
  tModalDialog::~tModalDialog()
  {
    UserDebug(Destructor,"tModalDialog::~tModalDialog() destructor\n")
  }

//===================>>> tModalDialog::DialogCommand <<<==================
  void tModalDialog::DialogCommand(ItemVal id,ItemVal retval,CmdType ctype)
  {
    // After the user has selected a command from the dialog,
    // this routine is called with the id and retval.

    vNoticeDialog note(this);

    UserDebug1(CmdEvents,"tModalDialog::DialogCommand(id:%d)\n",id)

    switch (id)         // We will do some things depending on value
      {
        case mmBtn1:            // Button 1
            note.Notice(" Test 1 ");
            break;

        case mmBtn2:            // Button 2
            note.Notice(" Test 2 ");
            break;
      }

    // let default behavior handle Cancel and OK
    vModalDialog::DialogCommand(id,retval,ctype);
  }

tmodal.h

//========================================================
//  tmodal.h - Header file for tModalDialog class
//
//  Copyright 1995, Bruce E. Wampler, All Rights Reserved
//========================================================

#ifndef TMODAL_H
#define TMODAL_H

#include <v/vmodald.h>  // derived from vModalDialog

    class tModalDialog : public vModalDialog
      {
      public:           //---------------------------------------- public
        tModalDialog(vBaseWindow*);
        virtual ~tModalDialog();                // Destructor
        virtual void DialogCommand(ItemVal id, ItemVal retval,
                CmdType ctype);

      protected:        //--------------------------------------- protected

      private:          //--------------------------------------- private

      };
#endif

A.6 The Makefile

makefile

# Sample GNU make makefile for V tutorial application
CC      =       g++

# Note: Platform dependent for a Linux system

HOME    =       /home/bruce
X11INC  =       /usr/X11/include
X11LIB  =       /usr/X11R6/lib
Arch    =       intel
LIBS    =       -lV -lXaw -lXmu -lXt -lXext -lX11

VPATH   =       ../include

# Architecture dependent

VLibDir =       $(HOME)/v/lib/$(Arch)

oDir    =       ../obj/$(Arch)

LibDir  =       ../lib/$(Arch)

Bin     =       ../bin/$(Arch)

#--------------------------------------------------------------

# Typical flags for includes and libraries

CFLAGS  =       -O -I$(X11INC) -I$(HOME)

LFLAGS  =       -O -L$(X11LIB) -L$(VLibDir)

EXOBJS  =       $(oDir)/tutapp.o \
                $(oDir)/tdialog.o \
                $(oDir)/tmodal.o \
                $(oDir)/tcanvas.o \
                $(oDir)/tcmdwin.o

all:    $(Bin)/tutapp

$(Bin)/tutapp:  $(EXOBJS) $(VLibDir)/libV.a
        $(CC) -o $@ $(LFLAGS) $(EXOBJS) $(LIBS)

$(oDir)/tcanvas.o:      tcanvas.cpp v_defs.h tcanvas.h
        $(CC) -c $(CFLAGS) -o $@ $<                     

$(oDir)/tdialog.o:      tdialog.cpp v_defs.h tdialog.h
        $(CC) -c $(CFLAGS) -o $@ $<                     

$(oDir)/tmodal.o:       tmodal.cpp v_defs.h tmodal.h
        $(CC) -c $(CFLAGS) -o $@ $<                     

$(oDir)/tcmdwin.o:      tcmdwin.cpp v_defs.h tcmdwin.h
        $(CC) -c $(CFLAGS) -o $@ $<                     

$(oDir)/tutapp.o:       tutapp.cpp v_defs.h tdialog.h tmodal.h \
        tutapp.h tcmdwin.h
        $(CC) -c $(CFLAGS) -o $@ $<