1 /*
2 * $Id: display.c,v 1.9 2001/02/13 23:38:05 danny Exp $
3 *
4 * Copyright � 1992, 1993, 2001 Free Software Foundation, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this software; see the file COPYING. If not, write to
18 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #ifdef WITH_DMALLOC
26 #include <dmalloc.h>
27 #endif
28
29 #include <stdio.h>
30 #include "display.h"
31 #include "lists.h"
32 #include "cell.h"
33 #include "io-utils.h"
34
35 struct cell_display *
cell_display_of(struct display * disp,CELLREF r,CELLREF c)36 cell_display_of (struct display *disp, CELLREF r, CELLREF c)
37 {
38 int cols = disp->range.hc - disp->range.lc + 1;
39 if ( (r < disp->range.lr)
40 || (c < disp->range.lc)
41 || (r > disp->range.hr)
42 || (c > disp->range.hc))
43 return 0;
44 r -= disp->range.lr;
45 c -= disp->range.lc;
46 return disp->cells + r * cols + c;
47 }
48
49 void
free_display(disp)50 free_display (disp)
51 struct display *disp;
52 {
53 int rows = disp->range.hr - disp->range.lr + 1;
54 int cols = disp->range.hc - disp->range.lc + 1;
55 struct cell_display *cd = disp->cells;
56 int x, y;
57 for (y = 0; y < rows; ++y)
58 for (x = 0; x < cols; ++x)
59 {
60 if (cd->unclipped)
61 free (cd->unclipped);
62 if (cd->clipped)
63 free (cd->clipped);
64 ++cd;
65 }
66 free (disp->widths);
67 free (disp->heights);
68 free (disp->cells);
69 free (disp->rowy);
70 free (disp->colx);
71 }
72
73 void
damage(disp,cd)74 damage (disp, cd)
75 struct display *disp;
76 struct cell_display *cd;
77 {
78 if (cd && !cd->next_damaged)
79 {
80 cd->next_damaged = disp->damaged;
81 disp->damaged = cd;
82 }
83 }
84
85 int
pr_display_cell(struct display * disp,CELLREF r,CELLREF c,CELL * cp)86 pr_display_cell (struct display *disp, CELLREF r, CELLREF c, CELL *cp)
87 {
88 struct cell_display *cd = cell_display_of (disp, r, c);
89 xx_IntRectangle ir;
90 struct font_memo * new_font = 0;
91 char * new_unclipped = 0;
92 int new_type = 0;
93 int new_jst = 0;
94
95 if (!cd) /* Nowhere to show this */
96 return 0;
97 ir = &cd->layout;
98
99 if (cp && disp->widths[c - disp->range.lc]
100 && disp->heights[r - disp->range.lr])
101 {
102 new_unclipped = print_cell (cp);
103 if (!new_unclipped || *new_unclipped == '\0')
104 new_unclipped = 0;
105 else
106 {
107 new_type = GET_TYP (cp);
108 new_jst = GET_JST (cp);
109 new_font = cp->cell_font;
110 if (new_jst == JST_DEF)
111 new_jst = default_jst;
112 }
113 }
114
115
116 if (((!new_unclipped && !cd->unclipped)
117 || ((new_unclipped && cd->unclipped)
118 && !strcmp(cd->unclipped, new_unclipped)))
119 && (cd->font == new_font)
120 && (cd->cell_type == new_type)
121 && (cd->justification == new_jst))
122 return 0;
123
124 record_display_damage (disp, xx_IRx (ir), xx_IRy (ir),
125 xx_IRw (ir), xx_IRh (ir));
126 if (cd->unclipped)
127 {
128 free (cd->unclipped);
129 cd->unclipped = 0;
130 }
131 if (cd->clipped)
132 {
133 free (cd->clipped);
134 cd->clipped = 0;
135 }
136 cd->font = new_font;
137 cd->cell_type = new_type;
138 cd->justification = new_jst;
139 if (!cp || !GET_TYP (cp))
140 {
141 xx_IRinit (&cd->goal, 0, 0, 0, 0);
142 xx_IRinit (&cd->clip, 0, 0, 0, 0);
143 cd->unclipped = 0;
144 return 1;
145 }
146 cd->unclipped = ck_savestr (new_unclipped);
147 cd->clipped = 0;
148 disp->metric (cd, disp);
149 if (new_type == TYP_INT)
150 cd->numeric.integer = cp->c_z.c_l;
151 else if (new_type == TYP_FLT)
152 cd->numeric.dbl = cp->c_z.c_d;
153 else
154 {
155 cd->clipped = ck_savestr (cd->unclipped);
156 cd->clip = cd->goal;
157 }
158 return 1;
159 }
160
null_metric(cd,disp)161 static void null_metric (cd, disp)
162 struct cell_display * cd;
163 struct display * disp;
164 {}
165
166 static void
_build_display(disp,range,metric,vdata,scalep)167 _build_display (disp, range, metric, vdata, scalep)
168 struct display *disp;
169 struct rng *range;
170 cell_display_metric metric;
171 void *vdata;
172 int scalep;
173 {
174 /* This would be more useful if it handled scrolling. */
175 int r, c;
176 int rows = range->hr - range->lr + 1;
177 int cols = range->hc - range->lc + 1;
178 int x, y;
179 disp->range = *range;
180 disp->widths = (int *) ck_malloc (sizeof (int) * cols);
181 disp->heights = (int *) ck_malloc (sizeof (int) * rows);
182 disp->rowy = (int *) ck_malloc (sizeof (int) * rows);
183 disp->colx = (int *) ck_malloc (sizeof (int) * cols);
184 disp->metric = metric ? metric : null_metric;
185 disp->vdata = vdata;
186 disp->cells = ((struct cell_display *)
187 ck_calloc (sizeof (struct cell_display) * rows * cols));
188 disp->damaged = (struct cell_display *) disp;
189 for (x = 0, r = range->lr; r <= range->hr; ++r)
190 {
191 disp->rowy[r - range->lr] = x;
192 x += disp->heights[r - range->lr] = (scalep ? get_scaled_height : get_height) (r);
193 }
194 for (y = 0, c = range->lc; c <= range->hc; ++c)
195 {
196 disp->colx[c - range->lc] = y;
197 y += disp->widths[c - range->lc] = (scalep ? get_scaled_width : get_width) (c);
198 for (r = range->lr; r <= range->hr; ++r)
199 {
200 struct cell_display *cd = cell_display_of (disp, r, c);
201 cd->r = r;
202 cd->c = c;
203 pr_display_cell (disp, r, c, find_cell (r, c));
204 }
205 }
206 }
207
208 void
build_display(disp,range,metric,vdata)209 build_display (disp, range, metric, vdata)
210 struct display *disp;
211 struct rng *range;
212 cell_display_metric metric;
213 void *vdata;
214 {
215 _build_display (disp, range, metric, vdata, 1);
216 }
217
218 void
build_unscaled_display(disp,range,metric,vdata)219 build_unscaled_display (disp, range, metric, vdata)
220 struct display *disp;
221 struct rng *range;
222 cell_display_metric metric;
223 void *vdata;
224 {
225 _build_display (disp, range, metric, vdata, 0);
226 }
227
228 void
display_range(rng,disp,x,y,w,h)229 display_range (rng, disp, x, y, w, h)
230 struct rng *rng;
231 struct display *disp;
232 int x, y, w, h;
233 {
234 int t;
235 struct rng *winrng = &disp->range;
236 int *rowy = disp->rowy;
237 int *heights = disp->heights;
238 int *colx = disp->colx;
239 int *widths = disp->widths;
240 int rows = winrng->hr - winrng->lr + 1;
241 int cols = winrng->hc - winrng->lc + 1;
242
243 for (t = 0; t < rows - 1; ++t)
244 if (rowy[t] + heights[t] - 1 >= y)
245 break;
246 rng->lr = t + winrng->lr;
247
248 while (t < rows - 1)
249 {
250 if (rowy[t] + heights[t] >= y + h)
251 break;
252 t++;
253 }
254 rng->hr = t + winrng->lr;
255
256 for (t = 0; t < cols - 1; ++t)
257 if (colx[t] + widths[t] - 1 >= x)
258 break;
259 rng->lc = t + winrng->lc;
260
261 while (t < cols - 1)
262 {
263 if (colx[t] + widths[t] >= x + w)
264 break;
265 t++;
266 }
267 rng->hc = t + winrng->lc;
268 }
269
270 extern void
record_display_damage(disp,x,y,w,h)271 record_display_damage (disp, x, y, w, h)
272 struct display *disp;
273 int x, y, w, h;
274 {
275 CELLREF r, c;
276 struct rng rng;
277 display_range (&rng, disp, x, y, w, h);
278 for (r = rng.lr; r <= rng.hr && r > 0; ++r)
279 for (c = rng.lc; c <= rng.hc && c > 0; ++c)
280 damage (disp, cell_display_of (disp, r, c));
281 }
282
283
284 void
layout(disp)285 layout (disp)
286 struct display *disp;
287 {
288 int *widths = disp->widths;
289 int *heights = disp->heights;
290 int *rowy = disp->rowy;
291 int *colx = disp->colx;
292 int rows = disp->range.hr - disp->range.lr + 1;
293 int cols = disp->range.hc - disp->range.lc + 1;
294 int ri, ci;
295 struct cell_display *cd;
296
297 /* This assigns each non-empty cell's space to itself. The rest of the */
298 /* function allocates the space held by empty cells. */
299 for (cd = disp->cells, ri = 0; ri < rows; ++ri)
300 for (ci = 0; ci < cols; ++ci, ++cd)
301 {
302 cd->was_used_by = cd->used_by;
303 cd->used_by = cd->unclipped ? cd : 0;
304 }
305
306 for (ri = 0; ri < rows; ++ri)
307 for (ci = 0; ci < cols; ++ci)
308 {
309 struct cell_display *cd =
310 cell_display_of (disp, ri + disp->range.lr, ci + disp->range.lc);
311 if (cd->unclipped)
312 {
313 xx_IntRectangle gr = &cd->goal;
314 int xl = xx_IRxl (gr);
315 int xh = xx_IRxh (gr);
316 int yl = xx_IRyl (gr);
317 int rl_answer, rh_answer, cl_answer, ch_answer;
318 int rl, rh, cl, ch;
319 int rit, cit;
320 int xt, yt;
321
322 for (cl = ci, xt = colx[cl];
323 cl && (xt > xl);
324 --cl, xt = colx[cl]);
325 for (rl = ri, yt = rowy[rl];
326 rl && (yt > yl);
327 --rl, yt = rowy[rl]);
328 for (ch = ci, xt = colx[ch] + widths[ch];
329 (ch < (cols - 1)) && (xt < xh);
330 ++ch, xt = colx[ch] + widths[ch]);
331 rh = ri;
332 /* rl/h & cl/h bound the cells covered by the goal rectangle.
333 * Of these, at least ri, ci is unused. The goal here is to
334 * allocate additional cells for use by ri,ci.
335 */
336 for (rit = ri - 1; rit >= rl; --rit)
337 for (cit = cl; ci <= ch; ++cit)
338 {
339 struct cell_display *cdt = disp->cells + (rit * cols) + cit;
340 if (cdt->used_by)
341 goto got_rl;
342 }
343 got_rl:
344 ++rit;
345 rl_answer = rit;
346
347 for (rit = ri + 1; rit <= rh; ++rit)
348 for (cit = cl; ci <= ch; ++cit)
349 {
350 struct cell_display *cdt = disp->cells + (rit * cols) + cit;
351 if (cdt->used_by)
352 goto got_rh;
353 }
354 got_rh:
355 --rit;
356 rh_answer = rit;
357
358 for (cit = ci - 1; cit >= cl; --cit)
359 for (rit = rl_answer; rit <= rh_answer; ++rit)
360 {
361 struct cell_display *cdt = disp->cells + (rit * cols) + cit;
362 if (cdt->used_by)
363 goto got_cl;
364 }
365 got_cl:
366 ++cit;
367 cl_answer = cit;
368
369 for (cit = ci + 1; cit <= ch; ++cit)
370 for (rit = rl_answer; rit <= rh_answer; ++rit)
371 {
372 struct cell_display *cdt = disp->cells + (rit * cols) + cit;
373 if (cdt->used_by)
374 goto got_ch;
375 }
376 got_ch:
377 --cit;
378 ch_answer = cit;
379
380 for (rit = rl_answer; rit <= rh_answer; ++rit)
381 for (cit = cl_answer; cit <= ch_answer; ++cit)
382 {
383 struct cell_display *cdt = disp->cells + (rit * cols) + cit;
384 cdt->used_by = cd;
385 if (cdt->was_used_by != cdt->used_by)
386 {
387 damage (disp, cdt);
388 damage (disp, cdt->was_used_by);
389 }
390 }
391
392 xx_IRinit (&cd->layout,
393 colx[cl_answer], rowy[rl_answer],
394 colx[ch_answer] + widths[ch_answer] - colx[cl_answer],
395 rowy[rh_answer] + heights[rh_answer] - rowy[rl_answer]);
396 }
397 }
398
399 /* Unused cells are given to themselves. */
400 for (cd = disp->cells, ri = 0; ri < rows; ++ri)
401 for (ci = 0; ci < cols; ++ci, ++cd)
402 if (!cd->used_by)
403 {
404 cd->used_by = cd;
405 if (cd->was_used_by != cd)
406 {
407 damage (disp, cd);
408 damage (disp, cd->was_used_by);
409 }
410 xx_IRinit (&cd->layout, colx[ci], rowy[ri],
411 widths[ci], heights[ri]);
412 }
413 }
414