teapot-spreadsheet/src/common/cell.c
Glen Whitney 07bf78c7bb More color prep: define color aspects of a cell
This change does away with separate attributes foreground and background,
  opting for an array of color "aspects", where the aspect can vary
  over an enum which can either be FOREGROUND or BACKGROUND. This will allow
  writing a single set of color-editing code which can work either on the
  foreground or background color of a cell.
2019-08-03 12:42:32 -04:00

183 lines
4.6 KiB
C

#include "cell.h"
#include <assert.h>
#include <string.h>
#include "default.h"
#include "eval.h"
#include "main.h"
const ColorNum DefaultCN[] =
{ [FOREGROUND] = 0, [BACKGROUND] = 16, [NUM_COLOR_ASPECTS] = 255 };
/* initcellcontents - make a fresh cell into the "empty" one; don't worry
about freeing anything there, that will have been handled. */
void initcellcontents(Cell *fresh)
{
(void)memset(fresh->contents, 0, sizeof(fresh->contents));
fresh->label=(char*)0;
fresh->adjust=AUTOADJUST;
fresh->precision=-1;
fresh->shadowed=0;
fresh->bold=0;
fresh->underline=0;
for (ColorAspect a = FOREGROUND; a < NUM_COLOR_ASPECTS; ++a)
fresh->aspect[a] = DefaultCN[a];
fresh->scientific=DEF_SCIENTIFIC;
fresh->value.type=EMPTY;
fresh->resvalue.type=EMPTY;
fresh->locked=0;
fresh->ignored=0;
fresh->clock_t0=0;
fresh->clock_t1=0;
fresh->clock_t2=0;
}
/* getcont -- get contents */
Token **getcont(const Cell *cell, ContentVariety v)
{
if (cell == NULLCELL) return EMPTY_TVEC;
if (v == CONTINGENT)
v = (cell->clock_t0 && cell->contents[ITERATIVE]) ? ITERATIVE : BASE;
return cell->contents[v];
}
/* getadjust -- get cell adjustment */
Adjust getadjust(const Cell* cell)
{
if (cell == NULLCELL) return LEFT;
else if (cell->adjust == AUTOADJUST)
return (cell->value.type == INT || cell->value.type == FLOAT ? RIGHT : LEFT);
else return cell->adjust;
}
/* shadowed -- is cell shadowed? */
bool shadowed(const Cell *cell)
{
return (cell != NULLCELL) && cell->shadowed;
}
/* isbold -- is cell bold? */
bool isbold(const Cell* cell)
{
return (cell != NULLCELL) && cell->bold;
}
/* getcolor -- a color associated to cell */
ColorNum getcolor(const Cell* cell, ColorAspect aspect)
{
return cell == NULLCELL ? DefaultCN[aspect] : cell->aspect[aspect];
}
/* isunderline -- is cell underlined? */
bool underlined(const Cell *cell)
{
return (cell != NULLCELL) && cell->underline;
}
/* locked -- is cell locked? */
bool locked(const Cell *cell)
{
return (cell != NULLCELL) && cell->locked;
}
/* transparent -- is cell transparent? */
bool transparent(const Cell* cell)
{
return (cell != NULLCELL) && cell->transparent;
}
/* ignored -- is cell ignored? */
bool ignored(const Cell *cell)
{
return (cell != NULLCELL) && cell->ignored;
}
/* getscientific -- should value be displayed in scientific notation? */
bool getscientific(const Cell *cell )
{
return (cell == NULLCELL) ? DEF_SCIENTIFIC : cell->scientific;
}
/* getprecision -- get cell precision */
int getprecision(const Cell *cell)
{
if (cell == NULLCELL || cell->precision == -1) return def_precision;
return cell->precision;
}
/* getlabel -- get cell label */
const char *getlabel(const Cell* cell)
{
if (cell == NULLCELL || cell->label == (char*)0) return "";
return cell->label;
}
/* copytokens -- copy a sequence of tokens, possibly reallocating dest */
static void copytokens(Token*** totoks, Token** fromtoks)
{
size_t from_len = tveclen(fromtoks);
if (from_len == 0)
{
tvecfree(*totoks);
*totoks = EMPTY_TVEC;
return;
}
size_t to_len = tveclen(*totoks);
if (from_len > to_len || *totoks == fromtoks)
{
if (*totoks != fromtoks) tvecfree(*totoks);
*totoks = malloc((from_len+1)*sizeof(Token*));
(*totoks)[from_len] = NULLTOKEN;
} else {
tvecfreetoks(*totoks);
}
for (size_t i = 0; i<from_len; ++i) /* destination already has NULLTOKEN at end */
{
if (fromtoks[i] == NULLTOKEN) (*totoks)[i] = NULLTOKEN;
else
{
(*totoks)[i] = malloc(sizeof(Token));
*((*totoks)[i]) = tcopy(*(fromtoks[i]));
}
}
}
/* freecellcontents -- free the resources of the cell at destruction time */
void freecellcontents(Cell *faded)
{
tvecfree(faded->contents[BASE]);
tvecfree(faded->contents[ITERATIVE]);
tfree(&(faded->value));
tfree(&(faded->resvalue));
if (faded->label != (char*)0) {
free(faded->label);
}
}
/* copycell - copies one Cell to another, handling any allocation issues */
void copycell(Cell *to, const Cell *fromcell)
{
assert(to != NULLCELL);
if (to == fromcell) return;
freecellcontents(to);
if (fromcell != NULLCELL) {
memcpy(to, fromcell, sizeof(Cell));
copytokens(&(to->contents[BASE]), fromcell->contents[BASE]);
copytokens(&(to->contents[ITERATIVE]), fromcell->contents[ITERATIVE]);
if (fromcell->label != (char*)0) {
size_t len = strlen(fromcell->label);
to->label = strcpy(malloc(len+2), fromcell->label);
(to->label)[len] = '_';
(to->label)[len+1] = '\0';
}
to->value.type = EMPTY;
to->resvalue.type = EMPTY;
} else {
initcellcontents(to);
}
}