All pastes #129799 Raw Edit

Miscellany

public text v1 · immutable
#129799 ·published 2006-08-13 18:29 UTC
rendered paste body
/* 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;
}