home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1994 #1
/
monster.zip
/
monster
/
PROG_GEN
/
FACETV.ZIP
/
FACE_TV.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1994-01-05
|
18KB
|
668 lines
/************************************************************************
**
** @(#)face_tv.cpp 01/05/94 Chris Ahlstrom
**
** ------------------------
** 73340.26@compuserve.com
** ------------------------
**
** Let's slowly build a C++ version of the FACE_TV code. This
** main program serves as a fairly simple test-bed and demo program
** for the FACE_TV library.
**
** To build it, use the makefile provided.
**
** v. 1.31 Added ResponseDevice code to support interactive
** between the user and the program in experiments.
** It includes a "response test" command that just
** verifies that the button and screen code works
** properly.
**
** v. 1.30 Some old code is still in here... I've incorporated
** code to test a new way of handling configuration
** files. It is implemented by creating a
** SimpleConfiguration object.
**
** At present, any code in this library that deals
** with the FilePicker class is much more in danger of
** of being buggy.
**
** Also involved is a better way of handling error
** messages (the class provides a pointer to the
** error message) which doesn't fit into the
** errorHandler() scheme, alas.
**
*************************************************************************/
/************************************************************************
**
** MAIN_cpp used for defining variables
** FACE_TV_cpp used for definitions peculiar to FACE_TV
** PROGRAM_VERSION appears in banners
** FACE_DOS_PROMPT prompt that appears on DOS command line
** FACE_WILDCARD generic extension for FACE_TV-related files
**
*************************************************************************/
#define MAIN_cpp // only one of these per program
#define FACE_TV_cpp // only one of these per FACE_TV
#define PROGRAM_VERSION " 1.32" // Turbo Vision is 2nd generation
#define FACE_DOS_PROMPT "PROMPT='EXIT' returns to FACE$_$P$G"
#define FACE_WILDCARD "*.FAC"
#include <stdlib.h> // for exit(), random()
#include <conio.h> // for video modes
#include <iostream.h>
#include <fstream.h> // for ifstream
#include <stdio.h> // for puts() etc
#include <string.h> // for strlen etc
#include <ctype.h>
#define USE_GEN_ERRORS // include message buffer in announce.h
#define USE_YES_NO_BUTTONS // include YesNo indirectly in announce.h
#define USE_TURBO_VISION // use TV version of screenmsg()
#include "announce.h" // error message and general message code
#include "boxtools.h" // tools for global annunciator boxes
#include "face_tv.h" // a good description of the main program
#include "face_tv.men" // all the menu entries
#include "face_box.men" // a sample setup for the dialog box
#if defined(TESTHEAP) // { TESTHEAP
#include "heapview.h" // handy viewer for debugging heap problems
#endif // } TESTHEAP
#include "timerctl.h" // controlling timers (TimerControl class)
#include "tinpmous.h" // controlling numbers with the mouse
#include "tv_confg.h" // SimpleConfiguration class
#include "respwind.h" // ResponseDevice class
/************************************************************************
** Static bar pointers for the main program
*************************************************************************/
const NestBar *MenuBarApp::menuBar = &FACEMenuBar;
const StatusBar *MenuBarApp::statusBar = &FACEStatusBar;
/************************************************************************
** TFaceApp constructor
*************************************************************************/
TFaceApp::TFaceApp()
:
TProgInit // initialize the desktop
(
TFaceApp::initStatusLine,
TFaceApp::initMenuBar,
TFaceApp::initDeskTop
),
MenuBarApp (), // initialize menubar
TBox (deskTop, dacByteList, midByteList), // init dialog box
DosShell (FACE_DOS_PROMPT), // set up DOS prompt
appError (ERR_NONE), // start with no errors
#ifdef OLD_WAY
configFile (new FilePicker(deskTop)), // main file name
#endif
showBox ((TDialog *) NULL), // control box
equipmentConfig(0)
{
msgArea = new UserMessages(deskTop, genErrors, genErrorsLength);
/********************************************************************
** Should check the following for success (I do in FACE_WIN, but
** not here, tsk tsk.)
*********************************************************************/
equipmentConfig = new SimpleConfiguration
(
deskTop, "default.ftv", &equipmentList[0] // default extension "FTV"
);
/********************************************************************
** Let's give a simple test to a useful feature for converting
** old code to run with Turbo Vision, by letting the user replace
** puts() [or printf(), if the caller formats the string using
** sprintf()] calls with calls to screenmsg().
*********************************************************************/
testsWindow = (TWindowScreen *) 0;
if (testsWindow == (TWindowScreen *) 0)
{
testsWindow = startWindowScreen(deskTop);
(void) screenmsg
(
1, testsWindow, "FACE_TV messages system is running\n"
);
(void) screenmsg
(
1, testsWindow, "A second message\n\n\n\n\n\n\n\n\n\n"
);
(void) screenmsg
(
1, testsWindow,
"A third message to really test this sucker and see...\n\n\n"
"what it can handle. Done.\n=============================\n"
);
}
#if defined(TESTHEAP) // { TESTHEAP
TRect r = getExtent(); // create the heap view
r.a.x = r.b.x - 13;
r.a.y = r.b.y - 1;
heap = new THeapView(r);
insert(heap);
#endif // } TESTHEAP
initTFaceApp(); // set-up initial status
}
/************************************************************************
** TFaceApp destructor
**
** We don't need to delete any objects that have been inserted
** into the deskTop... the deskTop takes care of calling destroy()
** for any items still inserted into it (such as testsWindow).
**
*************************************************************************/
TFaceApp::~TFaceApp ()
{
#if defined(TESTHEAP) // { TESTHEAP
delete heap;
#endif // } TESTHEAP
if (equipmentConfig)
delete equipmentConfig;
if (msgArea)
delete msgArea;
}
/************************************************************************
** TFaceApp::initTFaceApp ()
**
** Very simple now, but might read configuration files later.
** C4350 is another option. I don't UNDERSTAND how these work.
** Can't get 50-line mode to come up, and the mouse can move way
** below the screen if DOS was in 50-line mode before you started
** the FACE_TV program!!!!
**
** For now, I like the behavior of matching the DOS screen mode
** better... if the mode is 50-line, use that, otherwise use the 25-line
** mode. So I've commented out the setScreenMode call.
**
** Maybe need a better way to handle this bloody issue.
**
** By the way, CONIO.H has more video mode integers than
** the smxxxx constants in Turbo Vision's SYSTEM.H. And don't bother
** checking... CONIO's constants match (in value) those in SYSTEM.
**
*************************************************************************/
void
TFaceApp::initTFaceApp ()
{
textMode = C80; // C80 is in conio.h
// textMode = C80 + C4350; // C80 is in conio.h
// setScreenMode(textMode); // fix the screen
}
/************************************************************************
** TFaceApp handleEvent ()
**
** Note that the old way of reading and writing configuration
** information is superceded. Note also that we could add a third
** configuration command denoted "Save As", copy the calls for the
** Write command to it, and remove the parameter [FORCE_NEW_NAME]
** (or change it to PREVIOUS_NAME_UNLESS_INACTIVE, an ugly alternative),
** to make it more like the standard Save (which normally uses
** the default name, unless none has been given yet).
**
** See the TV_CONFG modules for more information.
**
*************************************************************************/
void
TFaceApp::handleEvent
(
TEvent& event
)
{
ErrorCode he_error = ERR_NONE;
TApplication::handleEvent(event); // handle the TV stuff
if (event.what == evCommand)
{
switch (event.message.command)
{
case cmConfigWriteAs:
if (equipmentConfig)
(void) equipmentConfig->write(FORCE_NEW_NAME); // get new name
break;
case cmConfigWrite:
#ifdef OLD_WAY // can't handle error messages
configFile->fileDialog(FILE_WRITE, FACE_WILDCARD);
if (configFile->fileAction())
face_dialogs(FILE_WRITE, configFile->fileSpec());
#else
if (equipmentConfig)
(void) equipmentConfig->write();
break;
#endif
case cmConfigRead:
#ifdef OLD_WAY // can't handle error messages
configFile->fileDialog(FILE_READ, FACE_WILDCARD);
if (configFile->fileAction())
face_dialogs(FILE_READ, configFile->fileSpec());
#else
if (equipmentConfig)
(void) equipmentConfig->read(FORCE_NEW_NAME);
#endif
break;
case cmDOS_Cmd: // DOS shell
shell(); // shell out to DOS
redraw(); // redraw application screen
break;
case cmInfo:
msgArea->bannerHandler(FACE_TV_BANNER);
break;
case cmDacDialog:
(void) doDialog(&dacMenu, &dacDialog);
break;
case cmMidDialog:
(void) mappedDialog(&midMenu, &midDialog);
break;
case cmExpDialog:
(void) doDialog(&expMenu, &expDialog);
break;
case cmDelayDialog:
(void) doDialog(&delayWindow, &delayData);
break;
case cmResponseTest:
(void) respTest();
break;
case cmDelayTest:
(void) delayTest(&delayData);
break;
default:
he_error = ERR_COMMAND_UNIMPLEMENTED;
break;
}
clearEvent(event); // clear event after handling
}
if (he_error != ERR_NONE) // temp; avoid error message
{
msgArea->errorHandler(he_error);
he_error = ERR_NONE;
}
}
/************************************************************************
** TFaceApp::idle
**
** This routine provides a nice way to perform any background
** tasks. At present, the THeapView task is hardwired into place.
**
*************************************************************************/
void
TFaceApp::idle() // background task-master
{
TProgram::idle();
#if defined(TESTHEAP) // { TESTHEAP
heap->update();
#endif // } TESTHEAP
}
/************************************************************************
** TFaceApp::face_dialogs()
**
** Saves and restores all the dialog boxes; they amount to all
** the configuration we need.
**
** I should learn to use streams on this stuff; later dude.
**
*************************************************************************/
void
TFaceApp::face_dialogs
(
FileOperation rw,
char *fname
)
{
FILE *fptr;
size_t items; // number of items successfully written
if (rw == FILE_WRITE)
{
if ((fptr = fopen(fname, "wb")) != NULL)
{
//items = fwrite(&subDialog, sizeof(subDialog), 1, fptr);
items=0; //TEMPORARY
fclose(fptr);
}
else
{
msgArea->errorHandler(ERR_FILE_OPEN);
}
if (items < 1)
msgArea->errorHandler(ERR_FILE_WRITE);
}
else
{
if ((fptr = fopen(fname, "rb")) != NULL)
{
//items = fread(&subDialog, sizeof(subDialog), 1, fptr);
fclose(fptr);
}
else
{
msgArea->errorHandler(ERR_FILE_OPEN);
}
if (items < 1)
msgArea->errorHandler(ERR_FILE_READ);
}
}
/************************************************************************
** TFaceApp::respTest()
**
** Tests the response device system.
**
** It is important to note that objects that were inserted into
** the Turbo Vision deskTop cannot just be deleted. Instead, they
** must be destroyed(), as shown below!
**
** Very very important!!!
**
** Note that, for the response feedback calls, you can press either
** 1 or 2, and the feedback lights will be on the same side if the
** response matched the parameter (either 1 or 2) of the call. Otherwise,
** they will be on the opposite side.
**
*************************************************************************/
int
TFaceApp::respTest ()
{
int errcode = 0;
ResponseDevice *r = new ResponseDevice
(
KEYBOARD_RESPONSE,
TRect(2, 2, 70, 21), // bounds of the window
"Response Device", // window's title
1 // window number
);
if (r) // always check it... saves grief
{
deskTop->insert(r); // bring up the window
msgArea->bannerHandler
(
"Press the 1 or 2 key at each pause until the window disappears"
);
r->startScreen();
r->readyLight();
r->pause();
r->intervalLight(1);
r->pause();
r->intervalLight(2);
r->pause();
r->answerLight();
r->pause();
r->responseFeedback(1); // try answering with left...
r->pause();
r->responseFeedback(1); // then right... buttons
r->pause();
r->responseFeedback(2); // try answering with left...
r->pause();
r->responseFeedback(2); // then right... buttons
r->pause();
deskTop->destroy(r); // with TV, just can't delete it!!!
}
else
errcode = 1;
return errcode;
}
/************************************************************************
** TFaceApp::delayTest()
**
** Tests the response device system and the delay timer system.
** Similar to respTest(), but uses delays instead of pauses.
** The effect is to simulate the screen appearance (just once) of
** the 2AFC experimental procedure.
**
** Later, we can add random-interval generation and looping,
** to be halted by pressing both mouse buttons.
**
** I really don't like the way timers are handled here. I must
** rethink them.
**
*************************************************************************/
#define INTERVAL_MAX 2
int
TFaceApp::delayTest
(
DelayParameters *delays
)
{
int errcode = 0;
TimerControl *firsttimer = 0;
TimerControl *timer = 0;
TimerControl *previoustimer = 0;
double dur;
int goodone = 0;
for (int i = 0; i < DELAY_MAX; i++)
{
dur = (double) delays->scaleFactor / 100.0;
dur *= delays->timerDelay[i];
timer = new TimerControl // make another timer
(
deskTop, // hook it to TV deskTop
delays->baseID + i, // give it an id number
(unsigned) dur, // pass the duration
TIMER_IGNORE_COUNT
);
if (timer)
{
goodone++;
if (i == 0)
firsttimer = timer;
else
timer->attach(previoustimer);
previoustimer = timer;
}
else
{
break;
}
}
if (goodone < DELAY_MAX) // some timers not get made?
{
deleteTimer(firsttimer);
msgArea->bannerHandler("Timer creation error(s)");
return errcode = 2;
}
TimerControl *before; // DELAY_BEFORE_INTERVAL
TimerControl *stim; // DELAY_FOR_STIMULUS
TimerControl *between; // DELAY_BETWEEN_INTERVAL
TimerControl *feedback; // DELAY_FOR_FEEDBACK
before = firsttimer;
stim = before->next();
between = stim->next();
feedback = between->next();
ResponseDevice *r = new ResponseDevice
(
expDialog.responseDevice, // instead of KEYBOARD_RESPONSE,
TRect(2, 2, 70, 21), // bounds of the window
"Response Device", // window's title
1 // window number
);
if (r) // always check it... saves grief
{
deskTop->insert(r); // bring up the window
msgArea->bannerHandler
(
"Press the 1 or 2 key after the 4 lights blink"
);
/****************************************************************
** As you can see, we use a linked list of timers. Don't get
** yourself thinking that we have an array of timers.
*****************************************************************/
int mkey; // the response made by user
r->startScreen();
r->readyLight();
errcode = before->timerDelay();
for (int interval = 1; interval <= INTERVAL_MAX; interval++)
{
r->intervalLight(interval);
errcode = stim->timerDelay();
if (interval < INTERVAL_MAX)
errcode = between->timerDelay();
}
r->answerLight();
mkey = r->responseFeedback(1);
if (mkey != BOTH_BUTTONS)
errcode = feedback->timerDelay();
deskTop->destroy(r); // with TV, just can't delete it!!!
if (mkey == BOTH_BUTTONS)
msgArea->bannerHandler("You aborted! No problem...");
}
else
errcode = 1;
deleteTimer(firsttimer);
return errcode;
}
/************************************************************************
** Sample control-function for FACE_TV
**
** All this function does is display the value on the desktop
** in a little dialog box. As the mouse moves, both the original
** field and the value should scroll together
*************************************************************************/
static TDialog *showBox = (TDialog *) NULL;
static TDeskTop *faceDeskTop; // indirect access to deskTop
int
showFloatInBox
(
double value
)
{
if (showBox)
{
closeBox(showBox, 0);
}
showBox = floatBox
(
faceDeskTop, 12, 10, "Ctrl", value
);
return 0; // bogus error code for now
}
/************************************************************************
** FACE_TV main routine
**
** Normally, we'd just declare "TFaceApp myApp;" and do a
** "myApp.run()", but we need to test if it was created, for error-
** checking.
**
*************************************************************************/
int
main()
{
TFaceApp *myApp = new TFaceApp();
if (myApp)
{
faceDeskTop = myApp->tBoxTop; // need global access to desktop
myApp->run(); // run the main program loop
if (showBox) // did we leave a showBox open?
closeBox(showBox, 0); // yes, get rid of it
delete myApp; // get rid of everything
return 0; // everything worked
}
else
{
return 1; // could not run the program
}
}