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