~ubuntu-branches/ubuntu/hardy/texmacs/hardy

« back to all changes in this revision

Viewing changes to src/Typeset/Table/table.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Ralf Treinen
  • Date: 2004-04-19 20:34:00 UTC
  • Revision ID: james.westby@ubuntu.com-20040419203400-g4e34ih0315wcn8v
Tags: upstream-1.0.3-R2
ImportĀ upstreamĀ versionĀ 1.0.3-R2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
/******************************************************************************
 
3
* MODULE     : table.cpp
 
4
* DESCRIPTION: Tables and cells of tables
 
5
* COPYRIGHT  : (C) 1999  Joris van der Hoeven
 
6
*******************************************************************************
 
7
* This software falls under the GNU general public license and comes WITHOUT
 
8
* ANY WARRANTY WHATSOEVER. See the file $TEXMACS_PATH/LICENSE for more details.
 
9
* If you don't have this file, write to the Free Software Foundation, Inc.,
 
10
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
11
******************************************************************************/
 
12
 
 
13
#include "Table/table.hpp"
 
14
#include "Boxes/construct.hpp"
 
15
#include "Format/format.hpp"
 
16
 
 
17
lazy make_lazy_paragraph (edit_env env, array<box> bs, path ip);
 
18
 
 
19
/******************************************************************************
 
20
* Tables
 
21
******************************************************************************/
 
22
 
 
23
table_rep::table_rep (edit_env env2, int status2, int i0b, int j0b):
 
24
  var (""), env (env2), status (status2), i0 (i0b), j0 (j0b),
 
25
  T (NULL), nr_rows (0), width (0), height (0) {}
 
26
 
 
27
table_rep::~table_rep () {
 
28
  if (T != NULL) {
 
29
    int i;
 
30
    for (i=0; i<nr_rows; i++) delete[] T[i];
 
31
    delete[] T;
 
32
  }
 
33
}
 
34
 
 
35
void
 
36
table_rep::display (bool flag) {
 
37
  int i, j;
 
38
  if (flag) cout << "---------------------------------------------------------------------------\n";
 
39
  else cout << "{ ";
 
40
  for (i=0; i<nr_rows; i++) {
 
41
    cout << "[ ";
 
42
    for (j=0; j<nr_cols; j++)
 
43
      if (!nil (T[i][j])) {
 
44
        cell C= T[i][j];
 
45
        if (j != 0) cout << ", ";
 
46
        if (!nil (C->b)) cout << C->b;
 
47
        else if (!nil (C->T)) {
 
48
          cout << "subtable ";
 
49
          C->T->display (false);
 
50
        }
 
51
        else cout << "nil";
 
52
        if (!nil (C->D)) {
 
53
          cout << " & decoration ";
 
54
          C->D->display (false);
 
55
        }
 
56
      }
 
57
    cout << " ]";
 
58
    if (flag) cout << "\n";
 
59
    else if (i<nr_rows-1) cout << ", ";
 
60
  }
 
61
  if (flag) cout << "---------------------------------------------------------------------------\n";
 
62
  else cout << " }";
 
63
}
 
64
 
 
65
void
 
66
table_rep::typeset (tree t, path iq) {
 
67
  ip= iq;
 
68
  tree old_format= env->local_begin (CELL_FORMAT, tree (TFORMAT));
 
69
  tree new_format= old_format;
 
70
  if (!is_func (new_format, TFORMAT)) new_format= tree (TFORMAT);
 
71
  while (is_func (t, TFORMAT)) {
 
72
    new_format= join (new_format, t (0, N(t)-1));
 
73
    iq        = descend (iq, N(t)-1);
 
74
    t         = t[N(t)-1];
 
75
  }
 
76
  format_table (new_format);
 
77
  typeset_table (new_format, t, iq);
 
78
  env->local_end (CELL_FORMAT, old_format);
 
79
}
 
80
 
 
81
void
 
82
table_rep::typeset_table (tree fm, tree t, path ip) {
 
83
  int i;
 
84
  nr_rows= N(t);
 
85
  nr_cols= 0;
 
86
  T= new cell*[nr_rows];
 
87
  STACK_NEW_ARRAY (subformat, tree, nr_rows);
 
88
  extract_format (fm, subformat, nr_rows);
 
89
  for (i=0; i<nr_rows; i++)
 
90
    typeset_row (i, subformat[i], t[i], descend (ip, i));
 
91
  STACK_DELETE_ARRAY (subformat);
 
92
}
 
93
 
 
94
void
 
95
table_rep::typeset_row (int i, tree fm, tree t, path ip) {
 
96
  int j;
 
97
  nr_cols= N(t);
 
98
  T[i]= new cell[nr_cols];
 
99
  STACK_NEW_ARRAY (subformat, tree, nr_cols);
 
100
  extract_format (fm, subformat, nr_cols);
 
101
  for (j=0; j<nr_cols; j++) {
 
102
    cell& C= T[i][j];
 
103
    C= cell (env);
 
104
    C->typeset (subformat[j], t[j], descend (ip, j));
 
105
    C->row_span= min (C->row_span, nr_rows- i);
 
106
    C->col_span= min (C->col_span, nr_cols- j);
 
107
    if (hyphen == "y") C->row_span= 1;
 
108
  }
 
109
  STACK_DELETE_ARRAY (subformat);
 
110
}
 
111
 
 
112
/******************************************************************************
 
113
* Table formatting variables
 
114
******************************************************************************/
 
115
 
 
116
void
 
117
table_rep::format_table (tree fm) {
 
118
  int i, l= N(fm);
 
119
  for (i=0; i<l; i++)
 
120
    format_item (fm[i]);
 
121
 
 
122
  if (var->contains (TABLE_WIDTH)) {
 
123
    width= env->decode_length (env->exec (var[TABLE_WIDTH]));
 
124
    if (var->contains (TABLE_HMODE))
 
125
      hmode= as_string (env->exec (var[TABLE_HMODE]));
 
126
    else hmode= "exact";
 
127
  }
 
128
  else {
 
129
    width= 0;
 
130
    hmode= "";
 
131
  }
 
132
  if (var->contains (TABLE_HEIGHT)) {
 
133
    height= env->decode_length (env->exec (var[TABLE_HEIGHT]));
 
134
    if (var->contains (TABLE_VMODE))
 
135
      vmode= as_string (env->exec (var[TABLE_VMODE]));
 
136
    else vmode= "exact";
 
137
  }
 
138
  else {
 
139
    height= 0;
 
140
    vmode = "";
 
141
  }
 
142
  if (var->contains (TABLE_LSEP))
 
143
    lsep= env->decode_length (env->exec (var[TABLE_LSEP]));
 
144
  else lsep= 0;
 
145
  if (var->contains (TABLE_RSEP))
 
146
    rsep= env->decode_length (env->exec (var[TABLE_RSEP]));
 
147
  else rsep= 0;
 
148
  if (var->contains (TABLE_BSEP))
 
149
    bsep= env->decode_length (env->exec (var[TABLE_BSEP]));
 
150
  else bsep= 0;
 
151
  if (var->contains (TABLE_TSEP))
 
152
    tsep= env->decode_length (env->exec (var[TABLE_TSEP]));
 
153
  else tsep= 0;
 
154
  if (var->contains (TABLE_LBORDER))
 
155
    lborder= env->decode_length (env->exec (var[TABLE_LBORDER])) >> 1;
 
156
  else lborder= 0;
 
157
  if (var->contains (TABLE_RBORDER))
 
158
    rborder= env->decode_length (env->exec (var[TABLE_RBORDER])) >> 1;
 
159
  else rborder= 0;
 
160
  if (var->contains (TABLE_BBORDER))
 
161
    bborder= env->decode_length (env->exec (var[TABLE_BBORDER])) >> 1;
 
162
  else bborder= 0;
 
163
  if (var->contains (TABLE_TBORDER))
 
164
    tborder= env->decode_length (env->exec (var[TABLE_TBORDER])) >> 1;
 
165
  else tborder= 0;
 
166
  if (var->contains (TABLE_HALIGN))
 
167
    halign= as_string (env->exec (var[TABLE_HALIGN]));
 
168
  else halign= "l";
 
169
  if (var->contains (TABLE_VALIGN))
 
170
    valign= as_string (env->exec (var[TABLE_VALIGN]));
 
171
  else valign= "f";
 
172
  if (var->contains (TABLE_HYPHEN))
 
173
    hyphen= as_string (env->exec (var[TABLE_HYPHEN]));
 
174
  else hyphen= "n";
 
175
  if (var->contains (TABLE_ROW_ORIGIN))
 
176
    row_origin= as_int (env->exec (var[TABLE_ROW_ORIGIN]));
 
177
  else row_origin= 0;
 
178
  if (var->contains (TABLE_COL_ORIGIN))
 
179
    col_origin= as_int (env->exec (var[TABLE_COL_ORIGIN]));
 
180
  else col_origin= 0;
 
181
}
 
182
 
 
183
void
 
184
table_rep::format_item (tree with) {
 
185
  if (is_func (with, TWITH, 2))
 
186
    var (as_string (with[0]))= with[1];
 
187
}
 
188
 
 
189
/******************************************************************************
 
190
* Handling decorations and span
 
191
******************************************************************************/
 
192
 
 
193
void
 
194
table_rep::handle_decorations () {
 
195
  bool flag= true;
 
196
  int i, j, ii, jj, di, dj;
 
197
  array<int> ex_i1 (nr_rows), ex_i2 (nr_rows), off_i (nr_rows);
 
198
  array<int> ex_j1 (nr_cols), ex_j2 (nr_cols), off_j (nr_cols);
 
199
 
 
200
  /*** determine amount of decoration there is for each row and column ***/
 
201
  for (i=0; i<nr_rows; i++)
 
202
    ex_i1[i]= ex_i2[i]= 0;
 
203
  for (j=0; j<nr_cols; j++)
 
204
    ex_j1[j]= ex_j2[j]= 0;
 
205
  for (i=0; i<nr_rows; i++)
 
206
    for (j=0; j<nr_cols; j++) {
 
207
      cell C= T[i][j];
 
208
      if ((!nil (C)) && (!nil (C->T))) C->T->handle_decorations ();
 
209
      if ((!nil (C)) && (!nil (C->D))) {
 
210
        C->D->handle_decorations ();
 
211
        if (C->D->status == 1) {
 
212
          ii= i+ C->row_span- 1;
 
213
          jj= j+ C->col_span- 1;
 
214
          ex_i1[i ]= max (ex_i1[i ], C->D->i0);
 
215
          ex_j1[j ]= max (ex_j1[j ], C->D->j0);
 
216
          ex_i2[ii]= max (ex_i2[ii], C->D->nr_rows- 1- C->D->i0);
 
217
          ex_j2[jj]= max (ex_j2[jj], C->D->nr_cols- 1- C->D->j0);
 
218
          flag= false;
 
219
        }
 
220
      }
 
221
    }
 
222
  if (flag) return;
 
223
  for (i=0, ii=0; i<nr_rows; ii+=ex_i1[i]+ex_i2[i]+1, i++)
 
224
    off_i[i]= ii;
 
225
  for (j=0, jj=0; j<nr_cols; jj+=ex_j1[j]+ex_j2[j]+1, j++)
 
226
    off_j[j]= jj;
 
227
 
 
228
  /*** compute decorated table ***/
 
229
  cell** U;
 
230
  int new_rows= nr_rows, new_cols= nr_cols;
 
231
  for (i=0; i<nr_rows; i++) new_rows += ex_i1[i] + ex_i2[i];
 
232
  for (j=0; j<nr_cols; j++) new_cols += ex_j1[j] + ex_j2[j];
 
233
  U= new cell*[new_rows];
 
234
  for (i=0; i<new_rows; i++)
 
235
    U[i]= new cell[new_cols];
 
236
 
 
237
  for (i=0; i<nr_rows; i++)
 
238
    for (j=0; j<nr_cols; j++) {
 
239
      cell C= T[i][j];
 
240
      if (!nil (C)) {
 
241
        if ((!nil (C->D)) && (C->D->status==1)) {
 
242
          for (di=0; di<C->D->nr_rows; di++)
 
243
            for (dj=0; dj<C->D->nr_cols; dj++) {
 
244
              ii= di+ off_i[i]+ ex_i1[i]- C->D->i0;
 
245
              jj= dj+ off_j[j]+ ex_j1[j]- C->D->j0;
 
246
              U[ii][jj]= C->D->T[di][dj];
 
247
            }
 
248
          C->D= table ();
 
249
        }
 
250
        ii= off_i[i]+ ex_i1[i];
 
251
        jj= off_j[j]+ ex_j1[j];
 
252
        U[ii][jj]= C;
 
253
        ii= i+ C->row_span- 1;
 
254
        jj= j+ C->col_span- 1;
 
255
        C->row_span= off_i[ii]+ ex_i1[ii]+ 1- off_i[i]- ex_i1[i];
 
256
        C->col_span= off_j[jj]+ ex_j1[jj]+ 1- off_j[j]- ex_j1[j];
 
257
      }
 
258
    }
 
259
 
 
260
  /*** replace old table by new one ***/
 
261
  for (i=0; i<nr_rows; i++) delete[] T[i];
 
262
  delete[] T;
 
263
  T      = U;
 
264
  nr_rows= new_rows;
 
265
  nr_cols= new_cols;
 
266
  i0     = off_i[i0] + ex_i1[i0];
 
267
  j0     = off_j[j0] + ex_j1[j0];
 
268
}
 
269
 
 
270
void
 
271
table_rep::handle_span () {
 
272
  int i, j, ii, jj;
 
273
  for (i=0; i<nr_rows; i++)
 
274
    for (j=0; j<nr_cols; j++) {
 
275
      cell C= T[i][j];
 
276
      if (!nil (C)) {
 
277
        for (ii=0; ii<C->row_span; ii++)
 
278
          for (jj=0; jj<C->col_span; jj++)
 
279
            if ((ii != 0) || (jj != 0))
 
280
              T[i+ii][j+jj]= cell ();
 
281
        if (!nil (C->T)) C->T->handle_span ();
 
282
      }
 
283
    }
 
284
}
 
285
 
 
286
/******************************************************************************
 
287
* Each border is the maximum of the borders of its adjacent cells
 
288
******************************************************************************/
 
289
 
 
290
void
 
291
table_rep::merge_borders () {
 
292
  int i1, j1;
 
293
 
 
294
  for (i1=0; i1<nr_rows; i1++)
 
295
    for (j1=0; j1<(nr_cols-1); j1++) {
 
296
      cell C1= T[i1][j1], C2;
 
297
      if (!nil (C1)) {
 
298
        int i2, j2= j1 + C1->col_span;
 
299
        if (j2 >= nr_cols) continue;
 
300
        for (i2=i1; i2>=0; i2--) {
 
301
          C2= T[i2][j2];
 
302
          if (!nil (C2)) break;
 
303
        }
 
304
        if (!nil (C2)) {
 
305
          SI width= max (C1->rborder, C2->lborder);
 
306
          C1->rborder= C2->lborder= width;
 
307
          // ATTENTION: introduce new border variables when cells become lazy
 
308
        }
 
309
      }
 
310
    }
 
311
 
 
312
  for (i1=0; i1<(nr_rows-1); i1++)
 
313
    for (j1=0; j1<nr_cols; j1++) {
 
314
      cell C1= T[i1][j1], C2;
 
315
      if (!nil (C1)) {
 
316
        int i2= i1 + C1->row_span, j2;
 
317
        if (i2 >= nr_rows) continue;
 
318
        for (j2=j1; j2>=0; j2--) {
 
319
          C2= T[i2][j2];
 
320
          if (!nil (C2)) break;
 
321
        }
 
322
        if (!nil (C2)) {
 
323
          SI width= max (C1->bborder, C2->tborder);
 
324
          C1->bborder= C2->tborder= width;
 
325
          // ATTENTION: introduce new border variables when cells become lazy
 
326
        }
 
327
      }
 
328
    }
 
329
}
 
330
 
 
331
/******************************************************************************
 
332
* Subroutines for positioning
 
333
******************************************************************************/
 
334
 
 
335
static SI
 
336
sum (SI* a, int n) {
 
337
  int i, s=0;
 
338
  for (i=0; i<n; i++) s+= a[i];
 
339
  return s;
 
340
}
 
341
 
 
342
static double
 
343
sum (double* a, int n) {
 
344
  int i;
 
345
  double s=0.0;
 
346
  for (i=0; i<n; i++) s+= a[i];
 
347
  return s;
 
348
}
 
349
 
 
350
static void
 
351
blow_up (SI* w, SI* W, SI room, double* part, int n) {
 
352
  int i;
 
353
  double total= sum (part, n);
 
354
  if (total <= 0) {
 
355
    for (i=0; i<n; i++) part[i]= 1;
 
356
    total= n;
 
357
  }
 
358
  STACK_NEW_ARRAY (Part, double, n);
 
359
  for (i=0; i<n; i++) Part[i]= part[i];
 
360
 
 
361
  SI old_room= room;
 
362
  while (true) {
 
363
    for (i=0; i<n; i++)
 
364
      if (W[i] > w[i]) {
 
365
        SI extra= (SI) ((part[i]/total) * old_room);
 
366
        if (w[i]+extra >= W[i]) {
 
367
          room    -= (W[i]-w[i]);
 
368
          w[i]     = W[i];
 
369
          part[i]  = 0;
 
370
        }
 
371
      }
 
372
    total= sum (part, n);
 
373
    if (room <= 0) {
 
374
      STACK_DELETE_ARRAY (Part);
 
375
      return;
 
376
    }
 
377
    if ((total <= 0) || (room == old_room) || (room <= 0)) break;
 
378
    old_room= room;
 
379
  }
 
380
 
 
381
  if (total <= 0) {
 
382
    for (i=0; i<n; i++) part[i]= Part[i];
 
383
    total= sum (part, n);
 
384
  }
 
385
  for (i=0; i<n; i++) {
 
386
    SI extra= (SI) ((part[i]/total) * room);
 
387
    w[i] += extra;
 
388
  }
 
389
  STACK_DELETE_ARRAY (Part);
 
390
}
 
391
 
 
392
/******************************************************************************
 
393
* Horizontal positioning
 
394
******************************************************************************/
 
395
 
 
396
void
 
397
table_rep::compute_width (SI& tmw, SI& tlw, SI& trw) {
 
398
  position_columns ();
 
399
  tmw= x2 - x1;
 
400
  tlw= -x1;
 
401
  trw= x2;
 
402
}
 
403
 
 
404
void
 
405
table_rep::compute_widths (SI* mw, SI* lw, SI* rw, bool large) {
 
406
  int i, j;
 
407
  for (j=0; j<nr_cols; j++)
 
408
    mw[j]= lw[j]= rw[j]= 0;
 
409
 
 
410
  for (j=0; j<nr_cols; j++)
 
411
    for (i=0; i<nr_rows; i++) {
 
412
      cell C= T[i][j];
 
413
      if ((!nil (C)) && (C->col_span==1)) {
 
414
        SI cmw, clw, crw;
 
415
        C->compute_width (cmw, clw, crw, large);
 
416
        mw[j]= max (mw[j], cmw);
 
417
        lw[j]= max (lw[j], clw);
 
418
        rw[j]= max (rw[j], crw);
 
419
        mw[j]= max (mw[j], lw[j] + rw[j]);
 
420
      }
 
421
    }
 
422
 
 
423
  for (j=0; j<nr_cols; j++)
 
424
    for (i=0; i<nr_rows; i++) {
 
425
      cell C= T[i][j];
 
426
      if ((!nil (C)) && (C->col_span!=1)) {
 
427
        SI cmw, clw, crw;
 
428
        C->compute_width (cmw, clw, crw, large);
 
429
        SI tot= sum (mw+j, C->col_span);
 
430
        if (cmw > tot) mw[j] += cmw - tot;
 
431
      }
 
432
    }
 
433
}
 
434
 
 
435
void
 
436
table_rep::compute_horizontal_parts (double* part) {
 
437
  int i, j;
 
438
  for (j=0; j<nr_cols; j++) part[j]= 0.0;
 
439
  for (j=0; j<nr_cols; j++)
 
440
    for (i=0; i<nr_rows; i++) {
 
441
      cell C= T[i][j];
 
442
      if (!nil (C))
 
443
        part[j]= max (part[j], C->hpart);
 
444
    }
 
445
}
 
446
 
 
447
void
 
448
table_rep::position_columns () {
 
449
  STACK_NEW_ARRAY (mw, SI, nr_cols);
 
450
  STACK_NEW_ARRAY (lw, SI, nr_cols);
 
451
  STACK_NEW_ARRAY (rw, SI, nr_cols);
 
452
  compute_widths (mw, lw, rw, false);
 
453
  if (width != 0) {
 
454
    SI hextra= max (width- sum (mw, nr_cols), 0);
 
455
    if (hextra > 0) {
 
456
      STACK_NEW_ARRAY (part, double, nr_cols);
 
457
      STACK_NEW_ARRAY (Mw, SI, nr_cols);
 
458
      STACK_NEW_ARRAY (Lw, SI, nr_cols);
 
459
      STACK_NEW_ARRAY (Rw, SI, nr_cols);
 
460
      compute_horizontal_parts (part);
 
461
      compute_widths (Mw, Lw, Rw, true);
 
462
      blow_up (mw, Mw, hextra, part, nr_cols);
 
463
      STACK_DELETE_ARRAY (part);
 
464
      STACK_DELETE_ARRAY (Mw);
 
465
      STACK_DELETE_ARRAY (Lw);
 
466
      STACK_DELETE_ARRAY (Rw);
 
467
    }
 
468
  }
 
469
 
 
470
  int i, j;
 
471
  for (j=0; j<nr_cols; j++)
 
472
    for (i=0; i<nr_rows; i++) {
 
473
      cell C= T[i][j];
 
474
      if (!nil (C)) {
 
475
        if (C->hyphen != "n") {
 
476
          C->width= mw[j];
 
477
          C->fit_horizontally ();
 
478
        }
 
479
        if (!nil (C->T)) {
 
480
          C->T->width= mw[j]- C->lborder- C->rborder;
 
481
          C->T->position_columns ();
 
482
        }
 
483
      }
 
484
    }
 
485
 
 
486
  SI xoff;
 
487
  if (halign == "l") xoff= 0;
 
488
  else if (halign == "c") xoff= -sum (mw, nr_cols) >> 1;
 
489
  else if (halign == "r") xoff= -sum (mw, nr_cols);
 
490
  else if (halign == "L") xoff= -lw[0];
 
491
  else if (halign == "C")
 
492
    xoff= -(sum (mw, nr_cols>>1)+ sum (mw, (nr_cols-1)>>1)+
 
493
            lw[nr_cols>>1]+ lw[(nr_cols-1)>>1]) >> 1;
 
494
  else if (halign == "R") xoff= -sum (mw, nr_cols-1)- lw[nr_cols-1];
 
495
  else xoff= -sum (mw, j0)- lw[j0];
 
496
 
 
497
  x1= xoff- lborder- lsep;
 
498
  for (j=0; j<nr_cols; j++) {
 
499
    for (i=0; i<nr_rows; i++) {
 
500
      cell C= T[i][j];
 
501
      if (!nil (C)) {
 
502
        SI tot= sum (mw+j, C->col_span);
 
503
        C->position_horizontally (xoff, tot, lw[j], rw[j+C->col_span-1]);
 
504
      }
 
505
    }
 
506
    xoff += mw[j];
 
507
  }
 
508
  x2= xoff+ rborder+ rsep;
 
509
  STACK_DELETE_ARRAY (mw);
 
510
  STACK_DELETE_ARRAY (lw);
 
511
  STACK_DELETE_ARRAY (rw);
 
512
}
 
513
 
 
514
/******************************************************************************
 
515
* Vertical positioning
 
516
******************************************************************************/
 
517
 
 
518
void
 
519
table_rep::compute_height (SI& tmh, SI& tbh, SI& tth) {
 
520
  position_rows ();
 
521
  tmh= y2 - y1;
 
522
  tbh= -y1;
 
523
  tth= y2;
 
524
}
 
525
 
 
526
void
 
527
table_rep::compute_heights (SI* mh, SI* bh, SI* th) {
 
528
  int i, j;
 
529
  for (i=0; i<nr_rows; i++)
 
530
    mh[i]= bh[i]= th[i]= 0;
 
531
 
 
532
  for (i=0; i<nr_rows; i++)
 
533
    for (j=0; j<nr_cols; j++) {
 
534
      cell C= T[i][j];
 
535
      if ((!nil (C)) && (C->row_span==1)) {
 
536
        SI cmh, cbh, cth;
 
537
        C->compute_height (cmh, cbh, cth);
 
538
        mh[i]= max (mh[i], cmh);
 
539
        bh[i]= max (bh[i], cbh);
 
540
        th[i]= max (th[i], cth);
 
541
        mh[i]= max (mh[i], bh[i] + th[i]);
 
542
      }
 
543
    }
 
544
 
 
545
  for (i=0; i<nr_rows; i++)
 
546
    for (j=0; j<nr_cols; j++) {
 
547
      cell C= T[i][j];
 
548
      if ((!nil (C)) && (C->row_span!=1)) {
 
549
        SI cmh, cbh, cth;
 
550
        C->compute_height (cmh, cbh, cth);
 
551
        SI tot= sum (mh+i, C->row_span);
 
552
        if (cmh > tot) mh[i] += cmh - tot;
 
553
      }
 
554
    }
 
555
}
 
556
 
 
557
void
 
558
table_rep::compute_vertical_parts (double* part) {
 
559
  int i, j;
 
560
  for (i=0; i<nr_rows; i++) part[i]= 0.0;
 
561
  for (i=0; i<nr_rows; i++)
 
562
    for (j=0; j<nr_cols; j++) {
 
563
      cell C= T[i][j];
 
564
      if (!nil (C))
 
565
        part[i]= max (part[i], C->vpart);
 
566
    }
 
567
}
 
568
 
 
569
void
 
570
table_rep::position_rows () {
 
571
  STACK_NEW_ARRAY (mh, SI, nr_rows);
 
572
  STACK_NEW_ARRAY (bh, SI, nr_rows);
 
573
  STACK_NEW_ARRAY (th, SI, nr_rows);
 
574
 
 
575
  compute_heights (mh, bh, th);
 
576
  if (height != 0) {
 
577
    SI vextra= max (height- sum (mh, nr_rows), 0);
 
578
    if (vextra > 0) {
 
579
      int i;
 
580
      STACK_NEW_ARRAY (part, double, nr_rows);
 
581
      STACK_NEW_ARRAY (Mh, SI, nr_rows);
 
582
      compute_vertical_parts (part);
 
583
      for (i=0; i<nr_rows; i++) Mh[i]= mh[i];
 
584
      blow_up (mh, Mh, vextra, part, nr_rows);
 
585
      STACK_DELETE_ARRAY (part);
 
586
      STACK_DELETE_ARRAY (Mh);
 
587
    }
 
588
  }
 
589
 
 
590
  int i, j;
 
591
  for (i=0; i<nr_rows; i++) {
 
592
    for (j=0; j<nr_cols; j++) {
 
593
      cell C= T[i][j];
 
594
      if ((!nil (C)) && (!nil (C->T))) {
 
595
        C->T->height= mh[j]- C->bborder- C->tborder;
 
596
        C->T->position_rows ();
 
597
      }
 
598
    }
 
599
  }
 
600
 
 
601
  SI yoff;
 
602
  if (valign == "t") yoff= 0;
 
603
  else if (valign == "c") yoff= sum (mh, nr_rows) >> 1;
 
604
  else if (valign == "f") yoff= (sum (mh, nr_rows) >> 1) + env->fn->yfrac;
 
605
  else if (valign == "b") yoff= sum (mh, nr_rows);
 
606
  else if (valign == "T") yoff= th[0];
 
607
  else if (valign == "C")
 
608
    yoff= (sum (mh, nr_rows>>1)+ sum (mh, (nr_rows-1)>>1)+
 
609
           th[nr_rows>>1]+ th[(nr_rows-1)>>1]) >> 1;
 
610
  else if (valign == "B") yoff= sum (mh, nr_rows-1)+ th[nr_rows-1];
 
611
  else yoff= sum (mh, i0)+ th[i0];
 
612
 
 
613
  y2= yoff+ tborder+ tsep;
 
614
  for (i=0; i<nr_rows; i++) {
 
615
    for (j=0; j<nr_cols; j++) {
 
616
      cell C= T[i][j];
 
617
      if (!nil (C)) {
 
618
        SI tot= sum (mh+i, C->row_span);
 
619
        C->position_vertically (yoff, tot, tot+ bh[i]- mh[i], th[i]);
 
620
        C->shift= -yoff+ tot- bh[i];
 
621
      }
 
622
    }
 
623
    yoff -= mh[i];
 
624
  }
 
625
  y1= yoff- bborder+ bsep;
 
626
 
 
627
  STACK_DELETE_ARRAY (mh);
 
628
  STACK_DELETE_ARRAY (bh);
 
629
  STACK_DELETE_ARRAY (th);
 
630
}
 
631
 
 
632
/******************************************************************************
 
633
* Generate table
 
634
******************************************************************************/
 
635
 
 
636
void
 
637
table_rep::finish () {
 
638
  int i, j;
 
639
  array<box> bs;
 
640
  array<SI>  x;
 
641
  array<SI>  y;
 
642
  for (i=0; i<nr_rows; i++)
 
643
    for (j=0; j<nr_cols; j++)
 
644
      if (!nil (T[i][j])) {
 
645
        cell C = T[i][j];
 
646
        C->finish ();
 
647
        bs << C->b;
 
648
        x  << C->x1;
 
649
        y  << C->y1;
 
650
      }
 
651
 
 
652
  box   tb = composite_box (ip, bs, x, y, false);
 
653
  SI    x1= tb->x1;
 
654
  SI    y1= tb->y1;
 
655
  SI    x2= tb->x2;
 
656
  SI    y2= tb->y2;
 
657
  color fg= env->col;
 
658
  b= cell_box (tb->ip, tb, 0, 0, x1, y1, x2, y2,
 
659
               lborder, rborder, bborder, rborder, fg, fg, true);
 
660
  SI Lsep= lsep+lborder, Rsep= rsep+rborder;
 
661
  SI Bsep= bsep+bborder, Tsep= tsep+tborder;
 
662
  if ((Lsep != 0) || (Rsep != 0) || (Bsep != 0) || (Tsep != 0))
 
663
    b= cell_box (b->ip, b, Lsep, 0, x1, y1-Bsep, x2+Lsep+Rsep, y2+Tsep,
 
664
                 0, 0, 0, 0, fg, fg, true);
 
665
}
 
666
 
 
667
array<box>
 
668
table_rep::var_finish () {
 
669
  if (hyphen == "n") {
 
670
    array<box> bs (1);
 
671
    finish ();
 
672
    bs[0]= b;
 
673
    return bs;
 
674
  }
 
675
 
 
676
  int i, j;
 
677
  array<box> stack;
 
678
  for (i=0; i<nr_rows; i++) {
 
679
    array<box> bs;
 
680
    array<SI>  x;
 
681
    array<SI>  y;
 
682
    for (j=0; j<nr_cols; j++)
 
683
      if (!nil (T[i][j])) {
 
684
        cell C = T[i][j];
 
685
        C->finish ();
 
686
        bs << C->b;
 
687
        x  << C->x1;
 
688
        y  << (C->y1 + C->shift);
 
689
      }
 
690
    if (N(bs)==0) continue;
 
691
 
 
692
    box   tb= composite_box (ip, bs, x, y, false);
 
693
    SI    BB= (i==(nr_rows-1)? bborder: 0);
 
694
    SI    TB= (i==0? tborder: 0);
 
695
    SI    BS= (i==(nr_rows-1)? bsep: 0);
 
696
    SI    TS= (i==0? tsep: 0);
 
697
    SI    x1= tb->x1 - lborder;
 
698
    SI    x2= tb->x2 + rborder;
 
699
    SI    y1= tb->y1 - BB;
 
700
    SI    y2= tb->y2 + TB;
 
701
    color fg= env->col;
 
702
    b= cell_box (tb->ip, tb, 0, 0, x1, y1, x2, y2,
 
703
                 lborder, rborder, BB, TB, fg, fg, true);
 
704
    SI Lsep= lsep+lborder, Rsep= rsep+rborder;
 
705
    SI Bsep= BS+BB, Tsep= TS+TB;
 
706
    if ((Lsep != 0) || (Rsep != 0) || (Bsep != 0) || (Tsep != 0))
 
707
      b= cell_box (b->ip, b, Lsep, 0, x1, y1-Bsep, x2+Lsep+Rsep, y2+Tsep,
 
708
                   0, 0, 0, 0, fg, fg, true);
 
709
    stack << b;
 
710
  }
 
711
  return stack;
 
712
}
 
713
 
 
714
/******************************************************************************
 
715
* Lazy tables
 
716
******************************************************************************/
 
717
 
 
718
struct lazy_table_rep: public lazy_rep {
 
719
  table T; // the table
 
720
  lazy_table_rep (table T2, path ip): lazy_rep (LAZY_TABLE, ip), T (T2) {}
 
721
  operator tree () { return "Table"; }
 
722
  lazy produce (lazy_type request, format fm);
 
723
  format query (lazy_type request, format fm);
 
724
};
 
725
 
 
726
struct lazy_table {
 
727
  EXTEND_NULL(lazy,lazy_table);
 
728
  inline lazy_table (table T, path ip):
 
729
    rep (new lazy_table_rep (T, ip)) { rep->ref_count= 1; }
 
730
};
 
731
EXTEND_NULL_CODE(lazy,lazy_table);
 
732
 
 
733
format
 
734
lazy_table_rep::query (lazy_type request, format fm) {
 
735
  if ((request == LAZY_BOX) && (fm->type == QUERY_VSTREAM_WIDTH)) {
 
736
    /* The following is still bugged
 
737
    SI tmw, tlw, trw;
 
738
    T->compute_width (tmw, tlw, trw); */
 
739
    SI tmw= 1;
 
740
    return make_format_width (tmw);
 
741
  }
 
742
  return lazy_rep::query (request, fm);
 
743
}
 
744
 
 
745
lazy
 
746
lazy_table_rep::produce (lazy_type request, format fm) {
 
747
  if (request == type) return this;
 
748
  if (request == LAZY_VSTREAM) {
 
749
    if (fm->type == FORMAT_VSTREAM) {
 
750
      format_vstream fs= (format_vstream) fm;
 
751
      if (T->var[TABLE_WIDTH] == "1par")
 
752
        T->width= fs->width;
 
753
    }
 
754
    T->merge_borders ();
 
755
    T->position_columns ();
 
756
    T->position_rows ();
 
757
    array<box> bs= T->var_finish ();
 
758
    lazy tmp= make_lazy_paragraph (T->env, bs, ip);
 
759
    return tmp->produce (request, fm);
 
760
  }
 
761
  return lazy_rep::produce (request, fm);
 
762
}
 
763
 
 
764
lazy
 
765
make_lazy_table (edit_env env, tree t, path ip) {
 
766
  table T (env);
 
767
  T->typeset (t, ip);
 
768
  T->handle_decorations ();
 
769
  T->handle_span ();
 
770
  return lazy_table (T, ip);
 
771
}
 
772
 
 
773
/******************************************************************************
 
774
* User interface
 
775
******************************************************************************/
 
776
 
 
777
box
 
778
typeset_as_table (edit_env env, tree t, path ip) {
 
779
  table T (env);
 
780
  T->typeset (t, ip);
 
781
  T->handle_decorations ();
 
782
  T->handle_span ();
 
783
  T->merge_borders ();
 
784
  T->position_columns ();
 
785
  T->position_rows ();
 
786
  T->finish ();
 
787
  return T->b;
 
788
}
 
789
 
 
790
array<box>
 
791
typeset_as_var_table (edit_env env, tree t, path ip) {
 
792
  table T (env);
 
793
  T->typeset (t, ip);
 
794
  T->handle_decorations ();
 
795
  T->handle_span ();
 
796
  T->merge_borders ();
 
797
  T->position_columns ();
 
798
  T->position_rows ();
 
799
  return T->var_finish ();
 
800
}