// -*- C++ -*- /* Copyright (C) 1989, 1990, 1991, 1992, 2004 Free Software Foundation, Inc. Written by James Clark (jjc@jclark.com) This file is part of groff. groff 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. groff 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 groff; see the file COPYING. If not, write to the Free Software Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */ // piles and matrices #include "eqn.h" #include "pbox.h" // SUP_RAISE_FORMAT gives the first baseline // BASELINE_SEP_FORMAT gives the separation between baselines int pile_box::compute_metrics(int style) { int i; for (i = 0; i < col.len; i++) col.p[i]->compute_metrics(style); printf(".nr " WIDTH_FORMAT " 0", uid); for (i = 0; i < col.len; i++) printf(">?\\n[" WIDTH_FORMAT "]", col.p[i]->uid); printf("\n"); printf(".nr " BASELINE_SEP_FORMAT " %dM", uid, baseline_sep+col.space); for (i = 1; i < col.len; i++) printf(">?(\\n[" DEPTH_FORMAT "]+\\n[" HEIGHT_FORMAT "]+%dM)", col.p[i-1]->uid, col.p[i]->uid, default_rule_thickness*5); // round it so that it's a multiple of the vertical resolution printf("/\\n(.V+(\\n(.V/2)*\\n(.V\n"); printf(".nr " SUP_RAISE_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d/2" "+%dM\n", uid, uid, col.len-1, axis_height - shift_down); printf(".nr " HEIGHT_FORMAT " \\n[" SUP_RAISE_FORMAT "]+\\n[" HEIGHT_FORMAT "]\n", uid, uid, col.p[0]->uid); printf(".nr " DEPTH_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d+\\n[" DEPTH_FORMAT "]-\\n[" SUP_RAISE_FORMAT "]\n", uid, uid, col.len-1, col.p[col.len-1]->uid, uid); return FOUND_NOTHING; } void pile_box::output() { int i; printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid); for (i = 0; i < col.len; i++) { switch (col.align) { case LEFT_ALIGN: break; case CENTER_ALIGN: printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'", uid, col.p[i]->uid); break; case RIGHT_ALIGN: printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'", uid, col.p[i]->uid); break; default: assert(0); } col.p[i]->output(); printf("\\h'-\\n[" WIDTH_FORMAT "]u'", col.p[i]->uid); switch (col.align) { case LEFT_ALIGN: break; case CENTER_ALIGN: printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'", col.p[i]->uid, uid); break; case RIGHT_ALIGN: printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'", col.p[i]->uid, uid); break; default: assert(0); } if (i != col.len - 1) printf("\\v'\\n[" BASELINE_SEP_FORMAT "]u'", uid); } printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid); printf("\\v'-(%du*\\n[" BASELINE_SEP_FORMAT "]u)'", col.len - 1, uid); printf("\\h'\\n[" WIDTH_FORMAT "]u'", uid); } pile_box::pile_box(box *pp) : col(pp) { } void pile_box::check_tabs(int level) { col.list_check_tabs(level); } void pile_box::debug_print() { col.debug_print("pile"); } int matrix_box::compute_metrics(int style) { int i, j; int max_len = 0; int space = 0; for (i = 0; i < len; i++) { for (j = 0; j < p[i]->len; j++) p[i]->p[j]->compute_metrics(style); if (p[i]->len > max_len) max_len = p[i]->len; if (p[i]->space > space) space = p[i]->space; } for (i = 0; i < len; i++) { printf(".nr " COLUMN_WIDTH_FORMAT " 0", uid, i); for (j = 0; j < p[i]->len; j++) printf(">?\\n[" WIDTH_FORMAT "]", p[i]->p[j]->uid); printf("\n"); } printf(".nr " WIDTH_FORMAT " %dM", uid, column_sep*(len-1)+2*matrix_side_sep); for (i = 0; i < len; i++) printf("+\\n[" COLUMN_WIDTH_FORMAT "]", uid, i); printf("\n"); printf(".nr " BASELINE_SEP_FORMAT " %dM", uid, baseline_sep+space); for (i = 0; i < len; i++) for (j = 1; j < p[i]->len; j++) printf(">?(\\n[" DEPTH_FORMAT "]+\\n[" HEIGHT_FORMAT "]+%dM)", p[i]->p[j-1]->uid, p[i]->p[j]->uid, default_rule_thickness*5); // round it so that it's a multiple of the vertical resolution printf("/\\n(.V+(\\n(.V/2)*\\n(.V\n"); printf(".nr " SUP_RAISE_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d/2" "+%dM\n", uid, uid, max_len-1, axis_height - shift_down); printf(".nr " HEIGHT_FORMAT " 0\\n[" SUP_RAISE_FORMAT "]+(0", uid, uid); for (i = 0; i < len; i++) printf(">?\\n[" HEIGHT_FORMAT "]", p[i]->p[0]->uid); printf(")>?0\n"); printf(".nr " DEPTH_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d-\\n[" SUP_RAISE_FORMAT "]+(0", uid, uid, max_len-1, uid); for (i = 0; i < len; i++) if (p[i]->len == max_len) printf(">?\\n[" DEPTH_FORMAT "]", p[i]->p[max_len-1]->uid); printf(")>?0\n"); return FOUND_NOTHING; } void matrix_box::output() { printf("\\h'%dM'", matrix_side_sep); for (int i = 0; i < len; i++) { int j; printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid); for (j = 0; j < p[i]->len; j++) { switch (p[i]->align) { case LEFT_ALIGN: break; case CENTER_ALIGN: printf("\\h'\\n[" COLUMN_WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'", uid, i, p[i]->p[j]->uid); break; case RIGHT_ALIGN: printf("\\h'\\n[" COLUMN_WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'", uid, i, p[i]->p[j]->uid); break; default: assert(0); } p[i]->p[j]->output(); printf("\\h'-\\n[" WIDTH_FORMAT "]u'", p[i]->p[j]->uid); switch (p[i]->align) { case LEFT_ALIGN: break; case CENTER_ALIGN: printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" COLUMN_WIDTH_FORMAT "]u/2u'", p[i]->p[j]->uid, uid, i); break; case RIGHT_ALIGN: printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" COLUMN_WIDTH_FORMAT "]u'", p[i]->p[j]->uid, uid, i); break; default: assert(0); } if (j != p[i]->len - 1) printf("\\v'\\n[" BASELINE_SEP_FORMAT "]u'", uid); } printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid); printf("\\v'-(%du*\\n[" BASELINE_SEP_FORMAT "]u)'", p[i]->len - 1, uid); printf("\\h'\\n[" COLUMN_WIDTH_FORMAT "]u'", uid, i); if (i != len - 1) printf("\\h'%dM'", column_sep); } printf("\\h'%dM'", matrix_side_sep); } matrix_box::matrix_box(column *pp) { p = new column*[10]; for (int i = 0; i < 10; i++) p[i] = 0; maxlen = 10; len = 1; p[0] = pp; } matrix_box::~matrix_box() { for (int i = 0; i < len; i++) delete p[i]; a_delete p; } void matrix_box::append(column *pp) { if (len + 1 > maxlen) { column **oldp = p; maxlen *= 2; p = new column*[maxlen]; memcpy(p, oldp, sizeof(column*)*len); a_delete oldp; } p[len++] = pp; } void matrix_box::check_tabs(int level) { for (int i = 0; i < len; i++) p[i]->list_check_tabs(level); } void matrix_box::debug_print() { fprintf(stderr, "matrix { "); p[0]->debug_print("col"); for (int i = 1; i < len; i++) { fprintf(stderr, " "); p[i]->debug_print("col"); } fprintf(stderr, " }"); } column::column(box *pp) : box_list(pp), align(CENTER_ALIGN), space(0) { } void column::set_alignment(alignment a) { align = a; } void column::set_space(int n) { space = n; } void column::debug_print(const char *s) { char c = '\0'; // shut up -Wall switch (align) { case LEFT_ALIGN: c = 'l'; break; case RIGHT_ALIGN: c = 'r'; break; case CENTER_ALIGN: c = 'c'; break; default: assert(0); } fprintf(stderr, "%c%s %d { ", c, s, space); list_debug_print(" above "); fprintf(stderr, " }"); }