📄 table.c
字号:
* Attempt to narrow the "widest_column" by one character. */ const Area::size_type old_column_width = column_widths_in_out[widest_column]; list<auto_ptr<LogicalCell> >::iterator i; Area::size_type new_column_width = 0; for (i = lcs_in_out->begin(); i != lcs_in_out->end(); ++i) { LogicalCell &lc = **i; if (lc.x + lc.w - 1 != widest_column) continue; // Not in this column. Area::size_type left_of_column = 0; for (int j = lc.x; j < widest_column; ++j) { left_of_column += column_widths_in_out[j] + column_spacing; } Area::size_type w = lc.width; if (w >= left_of_column + old_column_width) { auto_ptr<Area> tmp(lc.cell->format( left_of_column + old_column_width - 1, Area::LEFT // Yields better results than "lc.halign"! )); w = tmp->width(); if (w >= left_of_column + old_column_width) lc.minimized = true; } if (w > left_of_column + new_column_width) { new_column_width = w - left_of_column; } } column_widths_in_out[widest_column] = new_column_width; *table_width_in_out -= old_column_width - new_column_width;//cerr// << "Narrowed column "// << widest_column// << " from "// << old_column_width// << " to "// << new_column_width// << endl;//cerr << "table_width=" << *table_width_in_out << endl;//for (int z = 0; z < number_of_columns; ++z) {// cerr << "column_widths[" << z << "]=" << column_widths_in_out[z] << endl;//} return true;}/* * Compute the heights of each row. Take into account the cells of the row, * plus the cells above that "hang" into the row. * * As a side effect, format the table cells. */static voidcompute_row_heights( list<auto_ptr<LogicalCell> > *lcs_in_out, const int number_of_rows, const Area::size_type row_spacing, Area::size_type *const row_heights_return, const int column_spacing, const Area::size_type *column_widths){ { for (int y = 0; y < number_of_rows; y++) row_heights_return[y] = 0; } list<auto_ptr<LogicalCell> >::reverse_iterator i; for (i = lcs_in_out->rbegin(); i != lcs_in_out->rend(); ++i) { LogicalCell &lc(**i); Area::size_type w = (lc.w - 1) * column_spacing; for (int x = lc.x; x < lc.x + lc.w; ++x) w += column_widths[x]; lc.area.reset(lc.cell->format(w, lc.halign)); if (!lc.area.get()) continue;// cerr << "lc.halign=" << lc.halign << ", w=" << w << endl;// cerr// << "***" << *lc.area << "***" << endl <<// lc.area->width() << "x" << lc.area->height() << endl; Area::size_type h = (lc.h - 1) * row_spacing; { for (int y = lc.y; y < lc.y + lc.h; ++y) h += row_heights_return[y]; } if (lc.area->height() > h) { row_heights_return[lc.y + lc.h - 1] += lc.area->height() - h; } }}/* ------------------------------------------------------------------------- */// <TABLE> Attributes: ALIGN (processed) WIDTH (ignored) BORDER (processed)// CELLSPACING CELLPADDING (ignored)// <TR> Attributes: ALIGN VALIGN (processed)// <TD> Attributes: NOWRAP (ignored) ROWSPAN COLSPAN ALIGN VALIGN// (processed) WIDTH HEIGHT (ignored)Area *Table::format(Area::size_type w, int halign) const{ halign = get_attribute( attributes.get(), "ALIGN", halign, "LEFT", Area::LEFT, "CENTER", Area::CENTER, "RIGHT", Area::RIGHT, 0 ); // <TABLE> => default => no border // <TABLE BORDER> => "" => draw border // <TABLE BORDER=0> => "0" => no border // <TABLE BORDER=1> => "1" => draw border bool draw_border = get_attribute(attributes.get(), "BORDER", "0") != "0"; static const Area::size_type column_spacing = 1; static const Area::size_type row_spacing = 0; Area::size_type left_border_width = draw_border ? 1 : 0; Area::size_type right_border_width = draw_border ? 1 : 0; static const Area::size_type top_border_width = 0; static const Area::size_type bottom_border_width = 0; /* * Iterate through the table's cells and create a list of "LogicalCell"s. * Compute the positions and sizes of all cells, format their contents, and * compute the number of rows and columns. */ list<auto_ptr<LogicalCell> > lcs; int number_of_rows, number_of_columns; create_lcs( *this, w, left_border_width, right_border_width, column_spacing, &lcs, &number_of_rows, &number_of_columns ); /* * Now compute the column widths and the table width. */ auto_aptr<Area::size_type> column_widths = new Area::size_type[number_of_columns]; Area::size_type table_width; compute_widths( lcs, number_of_columns, column_spacing, left_border_width, right_border_width, &table_width, column_widths.get() ); /* * Narrow the widest column that can be narrowed, until the entire table is * narrow enough. */ while (table_width > w) { if (!narrow_table( &lcs, /* in/out */ number_of_columns, column_spacing, column_widths.get(), /* in/out */ &table_width /* in/out */ )) break; } /* * At this point, all cells are formatted such that the table width fits * into "w" (if possible). */ /* * Compute row heights. */ auto_aptr<Area::size_type> row_heights = new Area::size_type[number_of_rows]; compute_row_heights( &lcs, number_of_rows, row_spacing, row_heights.get(), column_spacing, column_widths.get() ); Area::size_type table_height = ( top_border_width + (number_of_rows - 1) * row_spacing + bottom_border_width ); { for (int y = 0; y < number_of_rows; y++) table_height += row_heights[y]; } /* * Everything is prepared... start drawing! */ auto_ptr<Area> res(new Area); { static int vspace_before = Formatting::getInt("TABLE.vspace.before", 0); res->prepend(vspace_before); } Area::size_type x0 = 0; if (halign != Area::LEFT && table_width < w) { if (halign == Area::CENTER) x0 += (w - table_width) / 2; else if (halign == Area::RIGHT) x0 += w - table_width; } /* * Draw the caption, if any. */ if (caption.get()) { auto_ptr<Area> cap(caption->format(table_width, Area::CENTER)); if (cap.get() && cap->height() >= 1) { cap->add_attribute(Cell::BOLD); res->insert(*cap, x0, 0); } } /* * Draw the top and the left border. */ Area::size_type y0 = res->height(); if (draw_border) { if (y0 == 0) y0 = 1; res->fill('|', x0, y0, left_border_width, table_height); // Some trickery: The top border underline is easily masked by the bold // caption, so remove the boldness where possible in favor of the // underline. { Cell *cells = (*res)[y0 - 1]; for (Area::size_type x = 0; x < res->width(); x++) { if (cells[x].character == ' ') cells[x].attribute = Cell::NONE; } } res->add_attribute( Cell::UNDERLINE, x0 + left_border_width, y0 - 1, table_width - left_border_width - right_border_width, 1 ); } /* * Draw the cells and their bottom and right borders. */ { const list<auto_ptr<LogicalCell> > &lcl(lcs); list<auto_ptr<LogicalCell> >::const_iterator i; for (i = lcl.begin(); i != lcl.end(); ++i) { const LogicalCell &lc = **i; // Calculate cell position. Area::size_type x = x0 + left_border_width, y = y0 + top_border_width; { for (int j = 0; j < lc.x; j++) x += column_widths[j] + column_spacing;} { for (int j = 0; j < lc.y; j++) y += row_heights [j] + row_spacing; } // Calculate cell dimensions. Area::size_type w = (lc.w - 1) * column_spacing; { for (int j = lc.x; j < lc.x + lc.w; j++) w += column_widths[j]; } Area::size_type h = (lc.h - 1) * row_spacing; { for (int j = lc.y; j < lc.y + lc.h; j++) h += row_heights[j]; } // Draw cell contents and borders. if (lc.area.get()) { res->insert(*lc.area, x, y, w, h, lc.halign, lc.valign); } if (draw_border) { // If the right neighbor cell bottom is flush with this cell's bottom, // then also underline the border between the two cells. bool underline_column_separator = false; { int lx = lc.x + lc.w, ly = lc.y + lc.h; list<auto_ptr<LogicalCell> >::const_iterator j; for (j = lcl.begin(); j != lcl.end(); ++j) { const LogicalCell &lc2 = **j; if (lc2.x == lx && lc2.y + lc2.h == ly) { underline_column_separator = true; break; } } } res->add_attribute( Cell::UNDERLINE, x, y + h - 1, // x, y w + underline_column_separator, 1 // w, h ); res->fill('|', x + w, y, 1, h); } } } { static int vspace_after = Formatting::getInt("TABLE.vspace.after", 0); res->append(vspace_after); } return res.release();}/* ------------------------------------------------------------------------- */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -