2
/******************************************************************************
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
******************************************************************************/
13
#include "Table/table.hpp"
14
#include "Boxes/construct.hpp"
15
#include "Format/format.hpp"
17
lazy make_lazy_paragraph (edit_env env, array<box> bs, path ip);
19
/******************************************************************************
21
******************************************************************************/
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) {}
27
table_rep::~table_rep () {
30
for (i=0; i<nr_rows; i++) delete[] T[i];
36
table_rep::display (bool flag) {
38
if (flag) cout << "---------------------------------------------------------------------------\n";
40
for (i=0; i<nr_rows; i++) {
42
for (j=0; j<nr_cols; j++)
45
if (j != 0) cout << ", ";
46
if (!nil (C->b)) cout << C->b;
47
else if (!nil (C->T)) {
49
C->T->display (false);
53
cout << " & decoration ";
54
C->D->display (false);
58
if (flag) cout << "\n";
59
else if (i<nr_rows-1) cout << ", ";
61
if (flag) cout << "---------------------------------------------------------------------------\n";
66
table_rep::typeset (tree t, path 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);
76
format_table (new_format);
77
typeset_table (new_format, t, iq);
78
env->local_end (CELL_FORMAT, old_format);
82
table_rep::typeset_table (tree fm, tree t, path ip) {
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);
95
table_rep::typeset_row (int i, tree fm, tree t, path ip) {
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++) {
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;
109
STACK_DELETE_ARRAY (subformat);
112
/******************************************************************************
113
* Table formatting variables
114
******************************************************************************/
117
table_rep::format_table (tree fm) {
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]));
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]));
142
if (var->contains (TABLE_LSEP))
143
lsep= env->decode_length (env->exec (var[TABLE_LSEP]));
145
if (var->contains (TABLE_RSEP))
146
rsep= env->decode_length (env->exec (var[TABLE_RSEP]));
148
if (var->contains (TABLE_BSEP))
149
bsep= env->decode_length (env->exec (var[TABLE_BSEP]));
151
if (var->contains (TABLE_TSEP))
152
tsep= env->decode_length (env->exec (var[TABLE_TSEP]));
154
if (var->contains (TABLE_LBORDER))
155
lborder= env->decode_length (env->exec (var[TABLE_LBORDER])) >> 1;
157
if (var->contains (TABLE_RBORDER))
158
rborder= env->decode_length (env->exec (var[TABLE_RBORDER])) >> 1;
160
if (var->contains (TABLE_BBORDER))
161
bborder= env->decode_length (env->exec (var[TABLE_BBORDER])) >> 1;
163
if (var->contains (TABLE_TBORDER))
164
tborder= env->decode_length (env->exec (var[TABLE_TBORDER])) >> 1;
166
if (var->contains (TABLE_HALIGN))
167
halign= as_string (env->exec (var[TABLE_HALIGN]));
169
if (var->contains (TABLE_VALIGN))
170
valign= as_string (env->exec (var[TABLE_VALIGN]));
172
if (var->contains (TABLE_HYPHEN))
173
hyphen= as_string (env->exec (var[TABLE_HYPHEN]));
175
if (var->contains (TABLE_ROW_ORIGIN))
176
row_origin= as_int (env->exec (var[TABLE_ROW_ORIGIN]));
178
if (var->contains (TABLE_COL_ORIGIN))
179
col_origin= as_int (env->exec (var[TABLE_COL_ORIGIN]));
184
table_rep::format_item (tree with) {
185
if (is_func (with, TWITH, 2))
186
var (as_string (with[0]))= with[1];
189
/******************************************************************************
190
* Handling decorations and span
191
******************************************************************************/
194
table_rep::handle_decorations () {
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);
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++) {
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);
223
for (i=0, ii=0; i<nr_rows; ii+=ex_i1[i]+ex_i2[i]+1, i++)
225
for (j=0, jj=0; j<nr_cols; jj+=ex_j1[j]+ex_j2[j]+1, j++)
228
/*** compute decorated table ***/
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];
237
for (i=0; i<nr_rows; i++)
238
for (j=0; j<nr_cols; j++) {
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];
250
ii= off_i[i]+ ex_i1[i];
251
jj= off_j[j]+ ex_j1[j];
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];
260
/*** replace old table by new one ***/
261
for (i=0; i<nr_rows; i++) delete[] T[i];
266
i0 = off_i[i0] + ex_i1[i0];
267
j0 = off_j[j0] + ex_j1[j0];
271
table_rep::handle_span () {
273
for (i=0; i<nr_rows; i++)
274
for (j=0; j<nr_cols; j++) {
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 ();
286
/******************************************************************************
287
* Each border is the maximum of the borders of its adjacent cells
288
******************************************************************************/
291
table_rep::merge_borders () {
294
for (i1=0; i1<nr_rows; i1++)
295
for (j1=0; j1<(nr_cols-1); j1++) {
296
cell C1= T[i1][j1], C2;
298
int i2, j2= j1 + C1->col_span;
299
if (j2 >= nr_cols) continue;
300
for (i2=i1; i2>=0; i2--) {
302
if (!nil (C2)) break;
305
SI width= max (C1->rborder, C2->lborder);
306
C1->rborder= C2->lborder= width;
307
// ATTENTION: introduce new border variables when cells become lazy
312
for (i1=0; i1<(nr_rows-1); i1++)
313
for (j1=0; j1<nr_cols; j1++) {
314
cell C1= T[i1][j1], C2;
316
int i2= i1 + C1->row_span, j2;
317
if (i2 >= nr_rows) continue;
318
for (j2=j1; j2>=0; j2--) {
320
if (!nil (C2)) break;
323
SI width= max (C1->bborder, C2->tborder);
324
C1->bborder= C2->tborder= width;
325
// ATTENTION: introduce new border variables when cells become lazy
331
/******************************************************************************
332
* Subroutines for positioning
333
******************************************************************************/
338
for (i=0; i<n; i++) s+= a[i];
343
sum (double* a, int n) {
346
for (i=0; i<n; i++) s+= a[i];
351
blow_up (SI* w, SI* W, SI room, double* part, int n) {
353
double total= sum (part, n);
355
for (i=0; i<n; i++) part[i]= 1;
358
STACK_NEW_ARRAY (Part, double, n);
359
for (i=0; i<n; i++) Part[i]= part[i];
365
SI extra= (SI) ((part[i]/total) * old_room);
366
if (w[i]+extra >= W[i]) {
372
total= sum (part, n);
374
STACK_DELETE_ARRAY (Part);
377
if ((total <= 0) || (room == old_room) || (room <= 0)) break;
382
for (i=0; i<n; i++) part[i]= Part[i];
383
total= sum (part, n);
385
for (i=0; i<n; i++) {
386
SI extra= (SI) ((part[i]/total) * room);
389
STACK_DELETE_ARRAY (Part);
392
/******************************************************************************
393
* Horizontal positioning
394
******************************************************************************/
397
table_rep::compute_width (SI& tmw, SI& tlw, SI& trw) {
405
table_rep::compute_widths (SI* mw, SI* lw, SI* rw, bool large) {
407
for (j=0; j<nr_cols; j++)
408
mw[j]= lw[j]= rw[j]= 0;
410
for (j=0; j<nr_cols; j++)
411
for (i=0; i<nr_rows; i++) {
413
if ((!nil (C)) && (C->col_span==1)) {
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]);
423
for (j=0; j<nr_cols; j++)
424
for (i=0; i<nr_rows; i++) {
426
if ((!nil (C)) && (C->col_span!=1)) {
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;
436
table_rep::compute_horizontal_parts (double* part) {
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++) {
443
part[j]= max (part[j], C->hpart);
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);
454
SI hextra= max (width- sum (mw, nr_cols), 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);
471
for (j=0; j<nr_cols; j++)
472
for (i=0; i<nr_rows; i++) {
475
if (C->hyphen != "n") {
477
C->fit_horizontally ();
480
C->T->width= mw[j]- C->lborder- C->rborder;
481
C->T->position_columns ();
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];
497
x1= xoff- lborder- lsep;
498
for (j=0; j<nr_cols; j++) {
499
for (i=0; i<nr_rows; i++) {
502
SI tot= sum (mw+j, C->col_span);
503
C->position_horizontally (xoff, tot, lw[j], rw[j+C->col_span-1]);
508
x2= xoff+ rborder+ rsep;
509
STACK_DELETE_ARRAY (mw);
510
STACK_DELETE_ARRAY (lw);
511
STACK_DELETE_ARRAY (rw);
514
/******************************************************************************
515
* Vertical positioning
516
******************************************************************************/
519
table_rep::compute_height (SI& tmh, SI& tbh, SI& tth) {
527
table_rep::compute_heights (SI* mh, SI* bh, SI* th) {
529
for (i=0; i<nr_rows; i++)
530
mh[i]= bh[i]= th[i]= 0;
532
for (i=0; i<nr_rows; i++)
533
for (j=0; j<nr_cols; j++) {
535
if ((!nil (C)) && (C->row_span==1)) {
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]);
545
for (i=0; i<nr_rows; i++)
546
for (j=0; j<nr_cols; j++) {
548
if ((!nil (C)) && (C->row_span!=1)) {
550
C->compute_height (cmh, cbh, cth);
551
SI tot= sum (mh+i, C->row_span);
552
if (cmh > tot) mh[i] += cmh - tot;
558
table_rep::compute_vertical_parts (double* part) {
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++) {
565
part[i]= max (part[i], C->vpart);
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);
575
compute_heights (mh, bh, th);
577
SI vextra= max (height- sum (mh, nr_rows), 0);
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);
591
for (i=0; i<nr_rows; i++) {
592
for (j=0; j<nr_cols; j++) {
594
if ((!nil (C)) && (!nil (C->T))) {
595
C->T->height= mh[j]- C->bborder- C->tborder;
596
C->T->position_rows ();
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];
613
y2= yoff+ tborder+ tsep;
614
for (i=0; i<nr_rows; i++) {
615
for (j=0; j<nr_cols; j++) {
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];
625
y1= yoff- bborder+ bsep;
627
STACK_DELETE_ARRAY (mh);
628
STACK_DELETE_ARRAY (bh);
629
STACK_DELETE_ARRAY (th);
632
/******************************************************************************
634
******************************************************************************/
637
table_rep::finish () {
642
for (i=0; i<nr_rows; i++)
643
for (j=0; j<nr_cols; j++)
644
if (!nil (T[i][j])) {
652
box tb = composite_box (ip, bs, x, y, false);
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);
668
table_rep::var_finish () {
678
for (i=0; i<nr_rows; i++) {
682
for (j=0; j<nr_cols; j++)
683
if (!nil (T[i][j])) {
688
y << (C->y1 + C->shift);
690
if (N(bs)==0) continue;
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;
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);
714
/******************************************************************************
716
******************************************************************************/
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);
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; }
731
EXTEND_NULL_CODE(lazy,lazy_table);
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
738
T->compute_width (tmw, tlw, trw); */
740
return make_format_width (tmw);
742
return lazy_rep::query (request, fm);
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")
755
T->position_columns ();
757
array<box> bs= T->var_finish ();
758
lazy tmp= make_lazy_paragraph (T->env, bs, ip);
759
return tmp->produce (request, fm);
761
return lazy_rep::produce (request, fm);
765
make_lazy_table (edit_env env, tree t, path ip) {
768
T->handle_decorations ();
770
return lazy_table (T, ip);
773
/******************************************************************************
775
******************************************************************************/
778
typeset_as_table (edit_env env, tree t, path ip) {
781
T->handle_decorations ();
784
T->position_columns ();
791
typeset_as_var_table (edit_env env, tree t, path ip) {
794
T->handle_decorations ();
797
T->position_columns ();
799
return T->var_finish ();