home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1994 #1
/
monster.zip
/
monster
/
PROG_GEN
/
FACETV.ZIP
/
RESPINTR.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1994-01-04
|
14KB
|
532 lines
/************************************************************************
**
** @(#)respintr.cpp 01/04/94 Chris Ahlstrom
**
** C++ version, requires Turbo Vision by Borland
**
** This module interfaces C++ with the standard FACE response
** light code (in FACE_TV.LIB), and with code for handling various kinds
** of button devices.
**
** This module has functions very similar to those of
** response.cpp, but this module only handles mouse events for
** a response box implemented in a window.
**
** This version of the "light()" function is based on the
** implementation of Fan-Gang Zeng (but now uses text to draw the
** square lights). It is similar to, but quite a bit more organized
** and safe than, the code in the MODAPP program's version of
** respwind.cpp/h.
**
** The procedure displays the following layout (note that, at
** present, display of the text strings is not implemented):
**
**
** --------- ---------
** | READY | | ANSWER |
** --------- ---------
** --------- ---------
** | | | |
** | | | |
** | | | |
** --------- ---------
**
** ---------- ----------
** |Interval 1| |Interval 2|
** ---------- ----------
** ---------- ----------
** | | | |
** | | | |
** | | | |
** ---------- ----------
**
**
** ---------- ----------
** |Response 1| |Response 2|
** ---------- ----------
** ---------- ----------
** | | | |
** | | | |
** | | | |
** ---------- ----------
**
**
** This layout is generated in three steps:
**
** 1. The words are displayed, with the RespWordAttribute,
** using a text display, at the start of the experiment.
** A call to "resp_setup()" does this.
**
** 2. All lights are turned on using a call to light().
**
** 3. The various sequences of lights are displayed,
** using calls to light().
**
** The lights are mapped onto a byte, as shown in the CONST
** section. Where ever a bit is set, the corresponding "light"
** gets turned on. Some convenient labels are added, too, to
** represent combinations of lights.
**
*************************************************************************/
#define RESPINTR_cpp
#include <stdio.h> // standard i/o
#include <conio.h> // console i/o
#include <ctype.h> // character-handling functions
#include <graphics.h> // Borland graphics library
#include "respintr.h" // ResponseInterior class
#include "respvga.h" // VGA response box parameters
extern "C" // avoid name-mangling
{
#include "math_aux.h" // simple math like iround()
#include "textlog.h" // getScreenModes()
}
/************************************************************************
** ResponseInterior constructor and destructor.
**
** Note that, since we allocate a semi-permanent textBox, it
** might prove wise to add an assignment operator and copy constructor.
**
*************************************************************************/
ResponseInterior::ResponseInterior
(
ResponseBox& virtualbox, // light-coordinates in virtual units
const TRect& bounds // size of the window
) :
TView(bounds)
{
graphBox = &virtualbox; // a global structure
textBox = new ResponseBox; // temporary structure
if (textBox)
{
textBox->background_color = graphBox->background_color;
textBox->back_fillstyle = graphBox->back_fillstyle;
}
//respBackground = graphBox->background_color;
//screen = TURBO_VISION_WINDOW;
Screen *sc = new Screen; // allocate a struct
if (sc)
{
(void) getScreenModes(sc); // obtain many parameters
respRows = sc->screen_rows; // store number of text rows
respColumns = sc->screen_columns; // store number of text columns
respPixelX = sc->screen_gmax_x; // store pixel depth
respPixelY = sc->screen_gmax_y; // store pixel width
delete sc; // get rid of struct
}
options = options | ofFramed; // frame the box
//options = options | ofPostProcess; // accept leftover events
growMode = gfGrowHiX | gfGrowHiY; // size same as window's
textBox->response_1.status = RESP_ON;
textBox->response_2.status = RESP_ON;
textBox->ready_light.status = RESP_ON;
textBox->answer_light.status = RESP_ON;
textBox->interval_1.status = RESP_ON;
textBox->interval_2.status = RESP_ON;
textBox->failure_light.status = RESP_ON;
}
ResponseInterior::~ResponseInterior ()
{
if (textBox)
delete textBox;
}
/************************************************************************
** boxAspectConvert()
**
** Generates the proper coordinates to specify the layout
** of a response box, given the type of response box settings in use
** for the current graphics monitor.
**
** In addition, the coordinates are scaled to fit inside a box
** of a particular size (in units of lines and characters).
**
** This routine is called in the draw() routine, which is overridden
** here. By calling it there, the size of the lights will somewhat
** follow the size of the box, if the user resizes it.
**
*************************************************************************/
void
ResponseInterior::boxAspectConvert
(
TRect *wbox // window box into which to fit it all
)
{
lightAspectConvert(wbox, graphBox->response_1, textBox->response_1);
lightAspectConvert(wbox, graphBox->response_2, textBox->response_2);
lightAspectConvert(wbox, graphBox->ready_light, textBox->ready_light);
lightAspectConvert(wbox, graphBox->answer_light, textBox->answer_light);
lightAspectConvert(wbox, graphBox->interval_1, textBox->interval_1);
lightAspectConvert(wbox, graphBox->interval_2, textBox->interval_2);
textAspectConvert(wbox, graphBox->failure_light, textBox->failure_light);
}
#if defined(__BORLANDC__)
#pragma warn -sig // { ignore double-to-int warning
#endif
/************************************************************************
** lightAspectConvert()
**
** Determines the coordinates of a response light relative to
** the response-box window in which it resides. All coordinates,
** whether in graphics modes or text modes, are converted to text-
** character cells.
**
** Also copies some other fields from the source (virtual) light.
**
** Guide to conversions. The "screen_" values are as per
** "screen.c" and "screen.h" in the FACE library.
**
** 1. Converting virtual coordinates to characters:
**
** a. screen_x = (virtual_x / VIRTmax) * screen_columns
** b. screen_y = (virtual_y / VIRTmax) * screen_rows
**
** 2. Converting virtual coordinates to pixels:
**
** a. screen_x = (virtual_x / VIRTmax) * screen_gmax_x
** b. screen_y = (virtual_y / VIRTmax) * screen_gmax_y
**
** This routine doesn't handle graphics modes yet, or at
** least, I haven't tested it.
**
*************************************************************************/
void
ResponseInterior::lightAspectConvert
(
TRect *wbox, // window box into which the light goes
ResponseLight& source, // pixel-coordinates of the light
ResponseLight& text // text-coordinate-offsets of the light
)
{
int va, vb;
double maxx;
double maxy;
double boxx = (double) (wbox->b.x - wbox->a.x);
double boxy = (double) (wbox->b.y - wbox->a.y);
text.fillstyle = source.fillstyle; // style of background
text.color = source.color; // color of response light
if (respPixelX == 0 || respPixelY == 0)
{ // we're in text mode
maxx = (boxx / VIRTmax);
maxy = (boxy / VIRTmax);
}
else
{ // we're in graphics mode
maxx = (respPixelX+1) / VIRTmax / boxx;
maxy = (respPixelY+1) / VIRTmax / boxy;
}
va = iround(source.x0 * maxx);
vb = iround(source.x1 * maxx);
if ((vb-va) <= 0) // keep it > 0
vb = va + 1;
text.x0 = va;
text.x1 = vb;
va = iround(source.y0 * maxy);
vb = iround(source.y1 * maxy);
if ((vb-va) <= 0) // keep it > 0
vb = va + 1;
text.y0 = va;
text.y1 = vb;
}
/************************************************************************
** textAspectConvert()
**
** Once the above works, fix this to suit.
**
*************************************************************************/
void
ResponseInterior::textAspectConvert
(
TRect *wbox, // window box into which the light goes
ResponseText& light, // pixel-coordinates of the light
ResponseText& text // text-coordinate-offsets of the light
)
{
double maxx = (double) (respPixelX + 1);
double maxy = (double) (respPixelY + 1);
double boxx = (double) (wbox->b.x - wbox->a.x);
double boxy = (double) (wbox->b.y - wbox->a.y);
if (maxx <= 0.0 || maxy <= 0.0)
{
maxx = 1.0;
maxy = 1.0;
}
text.x0 = iround((light.x0 / maxx) * boxx);
text.y0 = iround((light.y0 / maxy) * boxy);
}
#if defined(__BORLANDC__)
#pragma warn .sig // } put warning back to original state
#endif
/************************************************************************
** draw() override
*************************************************************************/
void
ResponseInterior::draw()
{
// uchar wcolor = (uchar) getColor(textBox->background_color);
uchar wcolor = (uchar) textBox->background_color;
TRect wbox = getExtent(); // size of the window
wbox.grow(-1, -1); // make it fit in window
boxAspectConvert(&wbox); // get new (maybe) sizes
for (int i = 0; i < size.y; i++) // for each line...
{
writeChar(0, i, RCELL, wcolor, size.x); // fill with colored space
}
for (int lite = FIRST_LIGHT; lite <= LAST_LIGHT; lite++)
{
switch (lite)
{
case RESPONSE_1:
lightDraw(&textBox->response_1);
break;
case RESPONSE_2:
lightDraw(&textBox->response_2);
break;
case READY_LIGHT:
lightDraw(&textBox->ready_light);
break;
case ANSWER_LIGHT:
lightDraw(&textBox->answer_light);
break;
case INTERVAL_1:
lightDraw(&textBox->interval_1);
break;
case INTERVAL_2:
lightDraw(&textBox->interval_2);
break;
case FAILURE_LIGHT:
// text draw;
break;
}
}
}
/************************************************************************
** lightDraw()
**
** Turns on/off the desired combinations of response lights.
** Draws the lights according to each light's status. This status is
** set by lightOn() or lightOff(), and the lights "wait" for the
** next order to be re-drawn all at once.
**
*************************************************************************/
void
ResponseInterior::lightDraw
(
ResponseLight *r
)
{
int width = r->x1 - r->x0 + 1;
uchar lcolor;
lcolor = r->status ? r->color : textBox->background_color;
for (int i = r->y0; i <= r->y1; i++) // each line in light
writeChar // fill with colored space
(
r->x0, i, RCELL, lcolor, width
);
}
/************************************************************************
**
** The following functions do not know about fonts and graphics.
** They are wholly text-based and Turbo Vision based.
**
*************************************************************************/
/************************************************************************
** light()
**
** Turns on/off the desired combinations of response lights.
** Doesn't draw the lights, just sets each status properly, then
** calls drawView() to draw the lights using draw().
**
*************************************************************************/
void
ResponseInterior::light
(
unsigned char light_mask
)
{
int lite, temp_mask;
for (lite = FIRST_LIGHT; lite <= LAST_LIGHT; lite++)
{
temp_mask = light_mask & 1; // get right-most bit
if (temp_mask != 0) // turn a light ON
{
switch (lite)
{
case RESPONSE_1:
lightOn(&textBox->response_1);
break;
case RESPONSE_2:
lightOn(&textBox->response_2);
break;
case READY_LIGHT:
lightOn(&textBox->ready_light);
break;
case ANSWER_LIGHT:
lightOn(&textBox->answer_light);
break;
case INTERVAL_1:
lightOn(&textBox->interval_1);
break;
case INTERVAL_2:
lightOn(&textBox->interval_2);
break;
case FAILURE_LIGHT:
textBox->failure_light.status = RESP_ON;
break;
default:
puts("Programmer: you turned on an unused light.\n");
break;
}
}
else
{ // turn a light OFF
switch (lite)
{
case RESPONSE_1:
lightOff(&textBox->response_1);
break;
case RESPONSE_2:
lightOff(&textBox->response_2);
break;
case READY_LIGHT:
lightOff(&textBox->ready_light);
break;
case ANSWER_LIGHT:
lightOff(&textBox->answer_light);
break;
case INTERVAL_1:
lightOff(&textBox->interval_1);
break;
case INTERVAL_2:
lightOff(&textBox->interval_2);
break;
case FAILURE_LIGHT:
textBox->failure_light.status = RESP_OFF;
break;
}
}
light_mask >>= 1; // shift to next bit
}
drawView(); // update the view
}
/************************************************************************
** lightOn()
** lightOff()
**
** Turns on or off a single light. Since drawing of the lights
** can be redone at any time, we must always have the current status
** of lights available. Hence, these two functions are very simple...
** they merely set or reset the state flag for the light.
**
*************************************************************************/
void
ResponseInterior::lightOn
(
ResponseLight *r
)
{
r->status = RESP_ON;
}
void
ResponseInterior::lightOff
(
ResponseLight *r
)
{
r->status = RESP_OFF;
}