/* Filename: Screen.cpp
* Size: 12.30kB
* Last Modified: Sat Jun 24 17:36:04 2006
* Author: Ben Hearsum
*
* This comment was automatically generated by header.pl
* http://www.wittydomain.com/software
*/
#include <new>
#include <deque>
#include <string.h>
#include "screen.h"
extern "C" {
#include "dtio.h"
}
using namespace std;
/* most commonly used constructor
* set data to safe values and initialize it
*/
Field::Field(int r, int c, int l, const char *s, bool edit) {
row = 0;
col = 0;
len = 0;
c_pos = 0;
d = NULL;
init(r, c, l, s, edit);
}
/* copy constructor */
Field::Field(const Field &right):row(0), col(0), len(0), c_pos(-1), d(NULL) {
*this = right;
}
/* default constructor -- set member data to safe values */
Field::Field():row(0), col(0), len(0), c_pos(-1), d(NULL) {
setData("", len);
}
/* garbage collection */
Field::~Field() {
if (d) {
delete [] d;
}
}
/* assignment operator
* returns a reference to the left operand
*/
const Field& Field::operator=(const Field &right) {
/* if the operands are different instances of Field */
if (this != &right) {
/* initialize the left operand to be the same as the right */
init(right.getRow(), right.getCol(), right.getLen(),
(char*)right.data(), right.editable());
}
return *this;
}
/* is-equal-to operator, necessary for the use of deques
* a Field is considered equal to another field if:
* the starting coordinates are the same, the length is the same,
* the data is the same, and the editability is the same
* returns 1 for true and 0 for false
*/
bool Field::operator==(const Field &right) {
bool ret = false;
if ((*this).row == right.row && (*this).col == right.col
&& (*this).len == right.len && (*this).is_editable == right.is_editable
&& (strcmp((*this).d, right.d) == 0)) {
ret = true;
}
return ret;
}
bool Field::operator!=(const Field &right) {
bool ret = false;
if ((*this).row != right.row || (*this).col != right.col
|| (*this).len != right.len || (*this).is_editable != right.is_editable
|| (strcmp((*this).d, right.d) != 0)) {
ret = true;
}
return ret;
}
/* initialize this field */
void Field::init(int r, int c, int width, const char *s, bool edit) {
setRow(r);
setCol(c);
setLen(width);
/* if a value is specified for s, set the data to it */
if (s) {
setData(s, len);
}
/* otherwise, set it to a safe value */
else {
setData("\0", len);
}
is_editable = edit;
}
/* display this field */
void Field::display() {
dtioDisplay(d, row, col, len);
}
/* displays the field and, if possible, puts it into edit mode
* returns the key used to exit edit mode if editable
* returns 0 if not editable
*/
int Field::edit(Screen *sptr) {
int ret = 0;
/* is the field editable? */
if (is_editable) {
/* set c_pos to 0 if it is the first time being edited */
if (c_pos == -1) {
setcPos(0);
}
/* if the requested cursor position is longer than the string
* put c_pos at the end of the string
*/
else if (c_pos > len) {
c_pos = len;
}
/* edit the string */
ret = dtioEdit(d, row, col, len, &c_pos);
}
else {
display();
}
return ret;
}
/* returns a pointer to a new copy of this field */
Field* Field::clone()const {
return new(std::nothrow) Field(row, col, len, d, is_editable);
}
/* set the data of the field */
void Field::setData(const char *s, int l) {
/* free the old one if necessary */
if (d) {
delete [] d;
}
/* allocate memory for a new one */
d = new char[l + 1];
if (d) {
/* write the new data and terminate the string */
strncpy(d, s, l);
d[l] = '\0';
}
}
/* row cannot exceed the visible amount of rows (dtioRows() - 1)
* it also must be positive
*/
void Field::setRow(int r) {
int max_y = dtioRows() - 1;
if (r < 0) {
row = 0;
}
else if (r > max_y) {
row = max_y;
}
else {
row = r;
}
}
/* same goes for col. it must be visible and greater than zero */
void Field::setCol(int c) {
int max_x = dtioColumns() - 1;
if (c < 0) {
col = 0;
}
else if (c > max_x) {
col = max_x;
}
else {
col = c;
}
}
/* the length of a field plus the starting column must be a visible column */
void Field::setLen(int l) {
int max_x = dtioColumns() - 1;
if ((col + l) > max_x) {
len = max_x - col;
}
else {
len = l;
}
}
/* c_pos must be greater than 0 but not more than 1 past the last character */
void Field::setcPos(int c) {
if (c < 0) {
c_pos = 0;
}
else if (c <= len) {
c_pos = c;
}
else {
c_pos = len;
}
}
/* the most common constructor for Screen
* adds a field to this Screen based on the arguments provided */
Screen::Screen(int row, int col, int len, const char *s, bool editable) {
f_pos = 0;
size = 0;
add(row, col, len, s, editable);
}
/* deconstructor does nothing (the deque handles memory management */
Screen::~Screen() {
for (int i = 0; i < size; i++) {
delete fields[i];
}
}
/* assignment operator
* copies each field in the deque of the right operand to the left operand
* returns a reference to the left operand
*/
Screen& Screen::operator=(const Screen &right) {
if (this != &right) {
for (int i = 0; i < size; i++) {
*this += *(fields[i]);
}
}
return *this;
}
/* adds the Field given as the right operand to this Screen */
Screen& Screen::operator+=(const Field &right) {
add(right);
return *this;
}
/* adds new field to the deque of this Screen based on the arguments provided
* returns the total number of fields in the screen
*/
int Screen::add(int row, int col, int len, const char *s, bool editable) {
if (size < MAX_FIELDS) {
fields[size] = new Field(row, col, len, s, editable);
size++;
}
return size;
}
/* makes a copy of the Field provided and appends it to fields */
int Screen::add(const Field &f) {
if (size < MAX_FIELDS) {
fields[size] = f.clone();
size++;
}
return size;
}
/* displays all of the Fields in this Screen */
void Screen::display(bool clear) {
/* if we need to clear the screen first, do so now */
if (clear) {
dtioClear();
}
/* display every field on the screen */
for (int i = 0; i < size; i++) {
(fields[i])->display();
}
dtioFlush();
}
/* edit the fields on the screen starting at '*pfield', if it exists
* if clear is true, clear the screen before editing
* tab and down both advance to the next field
* up moves to the previous field
* enter moves to the next field unless it is the last field on the screen
* this function returns the key used to exit edit mode
*/
int Screen::edit(int *pfield, bool clear) {
int editing = 1;
int key;
int row, col;
/* if pfield exists set f_pos to pfield */
f_pos = (pfield) ? *pfield : f_pos;
/* and check to make sure it is actually a field */
if (f_pos >= (size - 1)) {
f_pos = (size - 1);
}
/* display all the fields on the screen, clearing it if necessary */
display(clear);
/* find the next editable field */
int orig_f_pos = f_pos;
do {
if (fields[f_pos] == fields[size - 1]) {
f_pos = 0;
}
else {
f_pos++;
}
if (f_pos == orig_f_pos) {
editing = 0;
}
} while (! fields[f_pos]->editable() && orig_f_pos != f_pos);
/* edit the first field */
key = (fields[f_pos])->edit(this);
while (editing) {
switch(key) {
/* move down one editable field */
case DOWN:
case TAB:
/* find the next editable field */
do {
if (fields[f_pos] == fields[size - 1]) {
f_pos = 0;
}
else {
f_pos++;
}
} while (! fields[f_pos]->editable());
/* reset row/col and put the field into edit mode */
row = fields[f_pos]->getRow();
col = fields[f_pos]->getCol();
key = fields[f_pos]->edit(this);
break;
/* move up one editable field */
case UP:
/* find the next editable field */
do {
if (fields[f_pos] == fields[0]) {
f_pos = size - 1;
}
else {
f_pos--;
}
} while (! fields[f_pos]->editable());
/* reset row/col and put the field into edit mode */
row = fields[f_pos]->getRow();
col = fields[f_pos]->getCol();
key = fields[f_pos]->edit(this);
break;
/* if we are at the last field, exit edit mode */
case ENTER:
if (fields[f_pos] == fields[size - 1]) {
editing = 0;
}
/* otherwise, find the next editable field (like TAB/DOWN) */
else {
do {
if (fields[f_pos] == fields[size - 1]) {
f_pos = 0;
}
else {
f_pos++;
}
} while (! fields[f_pos]->editable());
/* reset row/col and put the field into mode */
row = fields[f_pos]->getRow();
col = fields[f_pos]->getCol();
key = fields[f_pos]->edit(this);
}
break;
/* exit edit mode */
case ESCAPE:
case PGUP:
case PGDN:
case F(1):
case F(2):
case F(3):
case F(4):
case F(5):
case F(6):
case F(7):
case F(8):
case F(9):
case F(10):
case F(11):
case F(12):
/* Field::edit returns 0 if the field cannot be edited */
case 0:
editing = 0;
break;
default:
break;
}
}
/* if pfield was passed in, set it to the current field */
if (pfield) {
*pfield = f_pos;
}
return key;
}
/* returns a pointer to the Field at 'n', or NULL if the Field doesn't exist */
Field* Screen::getField(int n) {
Field* ret = NULL;
if (n <= size) {
ret = fields[n];
}
return ret;
}
/* removes the Field at position 'n' if it exists
* returns the new number of Fields in the Screen
*/
int Screen::remove(int n) {
if (n >= 0 && n < size) {
delete fields[n];
for (int i = n; i < size - 1; i++) {
fields[i] = fields[i+1];
}
size--;
}
return size;
}
/* START OF LABEL CLASS */
Label::Label(int r, int c, int width, const char *s) {
row = 0;
col = 0;
len = 0;
str = NULL;
is_editable = false;
init(r, c, width, s);
}
void Label::init(int r, int c, int width, const char *s) {
setRow(r);
setCol(c);
setLen(width);
if (str) {
delete [] str;
}
if (s) {
str = (char*)s;
dynamic = false;
}
else {
str = new char[width + 1];
str[0] = '\0';
dynamic = true;
}
}
void Label::display() {
dtioDisplay(str, row, col, len);
}
Label *Label::clone()const {
return new(std::nothrow) Label(row, col, len, str);
}
Label::~Label() {
if (dynamic) {
if (str) {
delete [] str;
}
}
}
/* START OF RESPONSE CLASS */
Response::Response(int r, int c, const char *s, int ch, void (*fptr)(Screen*)) {
valid_chars = NULL;
response_f = NULL;
init(r, c, s, ch, fptr);
}
Response::~Response() {
if (valid_chars) {
delete [] valid_chars;
}
}
void Response::init(int r, int c, const char *s, int ch,
void (*fptr)(Screen *)) {
setRow(r);
setCol(c);
setLen(1);
setData(ch);
if (valid_chars) {
delete [] valid_chars;
}
valid_chars = new char[strlen(s) + 1];
strcpy(valid_chars, s);
response_f = fptr;
is_editable = true;
}
int Response::edit(Screen *sptr) {
bool editing = true;
int orig_d = d;
dtioCursor(row, col);
d = dtioGetchar();
display();
if (! index(valid_chars, d)) {
d = orig_d;
}
if ((! index(valid_chars, d)) && response_f) {
(*response_f)(sptr);
}
}
void Response::display() {
dtioCursor(row, col);
dtioPutchar(d);
}
Response* Response::clone()const {
return new(std::nothrow) Response(row, col, valid_chars, d, response_f);
}
/* START OF VFIELD CLASS */
VField::VField(int r, int c, int w, const char *s,
int (*fptr)(char [], Screen *)) {
d = NULL;
init(r, c, w, s, fptr);
}
VField::~VField() {
}
int VField::edit(Screen *sptr) {
bool editing = true;
int exit_key;
do {
exit_key = Field::edit();
if (exit_key != ESCAPE) {
if ((*validate_f)(d, sptr)) {
editing = false;
}
}
else {
editing = false;
}
} while (editing);
return exit_key;
}
/* set the data of the field */
void VField::setData(const char *s, int l) {
/* free the old one if necessary */
if (d) {
delete [] d;
}
/* allocate memory for a new one */
d = new char[l+1];
if (d) {
/* write the new data and terminate the string */
strncpy(d, s, l);
d[l] = '\0';
}
}
VField* VField::clone()const {
return new(std::nothrow) VField(row, col, len, d, validate_f);
}
void VField::init(int r, int c, int w, const char *s,
int (*fptr)(char [], Screen *)) {
setRow(r);
setCol(c);
setLen(w);
setData(s, w);
is_editable = true;
validate_f = fptr;
}