home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 22 gnu
/
22-gnu.zip
/
OLEO130S.ZIP
/
oleo130s.tar
/
oleo-1.3
/
display.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-03-27
|
11KB
|
419 lines
/* Copyright (C) 1992, 1993 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this software; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include "display.h"
#include "lists.h"
#include "cell.h"
#include "io-utils.h"
#if __STDC__
struct cell_display *
cell_display_of (struct display *disp, CELLREF r, CELLREF c)
#else
struct cell_display *
cell_display_of (disp, r, c)
struct display *disp;
CELLREF r;
CELLREF c;
#endif
{
int cols = disp->range.hc - disp->range.lc + 1;
if ( (r < disp->range.lr)
|| (c < disp->range.lc)
|| (r > disp->range.hr)
|| (c > disp->range.hc))
return 0;
r -= disp->range.lr;
c -= disp->range.lc;
return disp->cells + r * cols + c;
}
void
free_display (disp)
struct display *disp;
{
int rows = disp->range.hr - disp->range.lr + 1;
int cols = disp->range.hc - disp->range.lc + 1;
struct cell_display *cd = disp->cells;
int x, y;
for (y = 0; y < rows; ++y)
for (x = 0; x < cols; ++x)
{
if (cd->unclipped)
free (cd->unclipped);
if (cd->clipped)
free (cd->clipped);
++cd;
}
free (disp->widths);
free (disp->heights);
free (disp->cells);
free (disp->rowy);
free (disp->colx);
}
void
damage (disp, cd)
struct display *disp;
struct cell_display *cd;
{
if (cd && !cd->next_damaged)
{
cd->next_damaged = disp->damaged;
disp->damaged = cd;
}
}
#if __STDC__
int
pr_display_cell (struct display *disp, CELLREF r, CELLREF c, CELL *cp)
#else
int
pr_display_cell (disp, r, c, cp)
struct display *disp;
CELLREF r;
CELLREF c;
CELL *cp;
#endif
{
int cols = disp->range.hc - disp->range.lc + 1;
struct cell_display *cd =
&disp->cells[cols * (r - disp->range.lr) + (c - disp->range.lc)];
xx_IntRectangle ir = &cd->layout;
struct font_memo * new_font = 0;
char * new_unclipped = 0;
int new_type = 0;
int new_jst = 0;
if (cp && disp->widths[c - disp->range.lc]
&& disp->heights[r - disp->range.lr])
{
new_unclipped = print_cell (cp);
if (!new_unclipped || *new_unclipped == '\0')
new_unclipped = 0;
else
{
new_type = GET_TYP (cp);
new_jst = GET_JST (cp);
new_font = cp->cell_font;
if (new_jst == JST_DEF)
new_jst = default_jst;
}
}
if (((!new_unclipped && !cd->unclipped)
|| ((new_unclipped && cd->unclipped)
&& !strcmp(cd->unclipped, new_unclipped)))
&& (cd->font == new_font)
&& (cd->cell_type == new_type)
&& (cd->justification == new_jst))
return 0;
record_display_damage (disp, xx_IRx (ir), xx_IRy (ir),
xx_IRw (ir), xx_IRh (ir));
if (cd->unclipped)
{
free (cd->unclipped);
cd->unclipped = 0;
}
if (cd->clipped)
{
free (cd->clipped);
cd->clipped = 0;
}
cd->font = new_font;
cd->cell_type = new_type;
cd->justification = new_jst;
if (!cp || !GET_TYP (cp))
{
xx_IRinit (&cd->goal, 0, 0, 0, 0);
xx_IRinit (&cd->clip, 0, 0, 0, 0);
cd->unclipped = 0;
return 1;
}
cd->unclipped = ck_savestr (new_unclipped);
cd->clipped = 0;
disp->metric (cd, disp);
if (new_type == TYP_INT)
cd->numeric.integer = cp->c_z.c_l;
else if (new_type == TYP_FLT)
cd->numeric.dbl = cp->c_z.c_d;
else
{
cd->clipped = ck_savestr (cd->unclipped);
cd->clip = cd->goal;
}
return 1;
}
static void null_metric (cd, disp)
struct cell_display * cd;
struct display * disp;
{}
static void
_build_display (disp, range, metric, vdata, scalep)
struct display *disp;
struct rng *range;
cell_display_metric metric;
void *vdata;
int scalep;
{
/* This would be more useful if it handled scrolling. */
int r, c;
int rows = range->hr - range->lr + 1;
int cols = range->hc - range->lc + 1;
int x, y;
disp->range = *range;
disp->widths = (int *) ck_malloc (sizeof (int) * cols);
disp->heights = (int *) ck_malloc (sizeof (int) * rows);
disp->rowy = (int *) ck_malloc (sizeof (int) * rows);
disp->colx = (int *) ck_malloc (sizeof (int) * cols);
disp->metric = metric ? metric : null_metric;
disp->vdata = vdata;
disp->cells = ((struct cell_display *)
ck_calloc (sizeof (struct cell_display) * rows * cols));
disp->damaged = (struct cell_display *) disp;
for (x = 0, r = range->lr; r <= range->hr; ++r)
{
disp->rowy[r - range->lr] = x;
x += disp->heights[r - range->lr] = (scalep ? get_scaled_height : get_height) (r);
}
for (y = 0, c = range->lc; c <= range->hc; ++c)
{
disp->colx[c - range->lc] = y;
y += disp->widths[c - range->lc] = (scalep ? get_scaled_width : get_width) (c);
for (r = range->lr; r <= range->hr; ++r)
{
struct cell_display *cd = cell_display_of (disp, r, c);
cd->r = r;
cd->c = c;
pr_display_cell (disp, r, c, find_cell (r, c));
}
}
}
void
build_display (disp, range, metric, vdata)
struct display *disp;
struct rng *range;
cell_display_metric metric;
void *vdata;
{
_build_display (disp, range, metric, vdata, 1);
}
void
build_unscaled_display (disp, range, metric, vdata)
struct display *disp;
struct rng *range;
cell_display_metric metric;
void *vdata;
{
_build_display (disp, range, metric, vdata, 0);
}
void
display_range (rng, disp, x, y, w, h)
struct rng *rng;
struct display *disp;
int x, y, w, h;
{
int t;
struct rng *winrng = &disp->range;
int *rowy = disp->rowy;
int *heights = disp->heights;
int *colx = disp->colx;
int *widths = disp->widths;
int rows = winrng->hr - winrng->lr + 1;
int cols = winrng->hc - winrng->lc + 1;
for (t = 0; t < rows - 1; ++t)
if (rowy[t] + heights[t] - 1 >= y)
break;
rng->lr = t + winrng->lr;
while (t < rows - 1)
{
if (rowy[t] + heights[t] >= y + h)
break;
t++;
}
rng->hr = t + winrng->lr;
for (t = 0; t < cols - 1; ++t)
if (colx[t] + widths[t] - 1 >= x)
break;
rng->lc = t + winrng->lc;
while (t < cols - 1)
{
if (colx[t] + widths[t] >= x + w)
break;
t++;
}
rng->hc = t + winrng->lc;
}
extern void
record_display_damage (disp, x, y, w, h)
struct display *disp;
int x, y, w, h;
{
CELLREF r, c;
struct rng rng;
display_range (&rng, disp, x, y, w, h);
for (r = rng.lr; r <= rng.hr && r > 0; ++r)
for (c = rng.lc; c <= rng.hc && c > 0; ++c)
damage (disp, cell_display_of (disp, r, c));
}
void
layout (disp)
struct display *disp;
{
int *widths = disp->widths;
int *heights = disp->heights;
int *rowy = disp->rowy;
int *colx = disp->colx;
int rows = disp->range.hr - disp->range.lr + 1;
int cols = disp->range.hc - disp->range.lc + 1;
int ri, ci;
struct cell_display *cd;
/* This assigns each non-empty cell's space to itself. The rest of the */
/* function allocates the space held by empty cells. */
for (cd = disp->cells, ri = 0; ri < rows; ++ri)
for (ci = 0; ci < cols; ++ci, ++cd)
{
cd->was_used_by = cd->used_by;
cd->used_by = cd->unclipped ? cd : 0;
}
for (ri = 0; ri < rows; ++ri)
for (ci = 0; ci < cols; ++ci)
{
struct cell_display *cd =
cell_display_of (disp, ri + disp->range.lr, ci + disp->range.lc);
if (cd->unclipped)
{
xx_IntRectangle gr = &cd->goal;
int xl = xx_IRxl (gr);
int xh = xx_IRxh (gr);
int yl = xx_IRyl (gr);
int rl_answer, rh_answer, cl_answer, ch_answer;
int rl, rh, cl, ch;
int rit, cit;
int xt, yt;
for (cl = ci, xt = colx[cl];
cl && (xt > xl);
--cl, xt = colx[cl]);
for (rl = ri, yt = rowy[rl];
rl && (yt > yl);
--rl, yt = rowy[rl]);
for (ch = ci, xt = colx[ch] + widths[ch];
(ch < (cols - 1)) && (xt < xh);
++ch, xt = colx[ch] + widths[ch]);
rh = ri;
/* rl/h & cl/h bound the cells covered by the goal rectangle.
* Of these, at least ri, ci is unused. The goal here is to
* allocate additional cells for use by ri,ci.
*/
for (rit = ri - 1; rit >= rl; --rit)
for (cit = cl; ci <= ch; ++cit)
{
struct cell_display *cdt = disp->cells + (rit * cols) + cit;
if (cdt->used_by)
goto got_rl;
}
got_rl:
++rit;
rl_answer = rit;
for (rit = ri + 1; rit <= rh; ++rit)
for (cit = cl; ci <= ch; ++cit)
{
struct cell_display *cdt = disp->cells + (rit * cols) + cit;
if (cdt->used_by)
goto got_rh;
}
got_rh:
--rit;
rh_answer = rit;
for (cit = ci - 1; cit >= cl; --cit)
for (rit = rl_answer; rit <= rh_answer; ++rit)
{
struct cell_display *cdt = disp->cells + (rit * cols) + cit;
if (cdt->used_by)
goto got_cl;
}
got_cl:
++cit;
cl_answer = cit;
for (cit = ci + 1; cit <= ch; ++cit)
for (rit = rl_answer; rit <= rh_answer; ++rit)
{
struct cell_display *cdt = disp->cells + (rit * cols) + cit;
if (cdt->used_by)
goto got_ch;
}
got_ch:
--cit;
ch_answer = cit;
for (rit = rl_answer; rit <= rh_answer; ++rit)
for (cit = cl_answer; cit <= ch_answer; ++cit)
{
struct cell_display *cdt = disp->cells + (rit * cols) + cit;
cdt->used_by = cd;
if (cdt->was_used_by != cdt->used_by)
{
damage (disp, cdt);
damage (disp, cdt->was_used_by);
}
}
xx_IRinit (&cd->layout,
colx[cl_answer], rowy[rl_answer],
colx[ch_answer] + widths[ch_answer] - colx[cl_answer],
rowy[rh_answer] + heights[rh_answer] - rowy[rl_answer]);
}
}
/* Unused cells are given to themselves. */
for (cd = disp->cells, ri = 0; ri < rows; ++ri)
for (ci = 0; ci < cols; ++ci, ++cd)
if (!cd->used_by)
{
cd->used_by = cd;
if (cd->was_used_by != cd)
{
damage (disp, cd);
damage (disp, cd->was_used_by);
}
xx_IRinit (&cd->layout, colx[ci], rowy[ri],
widths[ci], heights[ri]);
}
}