so no part of the cell's content is lost (and in fact it is duplicated
across both pages). */
int *join_crossing[TABLE_N_AXES];
+
+ /* Minimum and maximum widths of columns based on headings.
+
+ For this purpose, a table has the following three regions:
+
+ +------------------+-------------------------------------------------+
+ | | column headings |
+ | +-------------------------------------------------+
+ | corner | |
+ | and | |
+ | row headings | data |
+ | | |
+ | | |
+ +------------------+-------------------------------------------------+
+
+ - width_ranges[TABLE_HORZ] controls the minimum and maximum width that
+ columns in the column headings will be based on the column headings
+ themselves. That is, these columns will have width at least
+ width_ranges[TABLE_HORZ][0] wide, and no more than
+ width_ranges[TABLE_HORZ][1] unless the data requires it.
+
+ - width_ranges[TABLE_VERT] controls the minimum and maximum width that
+ columns in the corner and row headings will be based on the corner and
+ row headings themselves. That is, these columns will have width at
+ least width_ranges[TABLE_VERT][0] wide, and no more than
+ width_ranges[TABLE_VERT][1]. (The corner and row headings don't have
+ data in their columns so data can't affect their widths.)
+ */
+ int width_ranges[TABLE_N_AXES][2];
};
static struct render_page *render_page_create (const struct render_params *,
- struct table *, int min_width);
+ struct table *, int min_width,
+ const struct pivot_table_look *);
struct render_page *render_page_ref (const struct render_page *page_);
static void render_page_unref (struct render_page *);
\f
/* Rendering utility functions. */
-/* Returns the line style to use for drawing a rule of the given TYPE. */
-static enum render_line_style
-rule_to_render_type (unsigned char type)
-{
- switch (type)
- {
- case TABLE_STROKE_NONE:
- return RENDER_LINE_NONE;
- case TABLE_STROKE_SOLID:
- return RENDER_LINE_SINGLE;
- case TABLE_STROKE_DASHED:
- return RENDER_LINE_DASHED;
- case TABLE_STROKE_THICK:
- return RENDER_LINE_THICK;
- case TABLE_STROKE_THIN:
- return RENDER_LINE_THIN;
- case TABLE_STROKE_DOUBLE:
- return RENDER_LINE_DOUBLE;
- default:
- NOT_REACHED ();
- }
-}
-
/* Returns the width of the rule in TABLE that is at offset Z along axis A, if
rendered with PARAMS. */
static int
/* Determine all types of rules that are present, as a bitmap in 'rules'
where rule type 't' is present if bit 2**t is set. */
- struct cell_color color;
unsigned int rules = 0;
int d[TABLE_N_AXES];
d[a] = z;
for (d[b] = 0; d[b] < table->n[b]; d[b]++)
- rules |= 1u << table_get_rule (table, a, d[H], d[V], &color);
+ rules |= 1u << table_get_rule (table, a, d[H], d[V]).stroke;
/* Turn off TABLE_STROKE_NONE because it has width 0 and we needn't bother.
However, if the device doesn't support margins, make sure that there is at
int width = 0;
for (size_t i = 0; i < TABLE_N_STROKES; i++)
if (rules & (1u << i))
- width = MAX (width, params->line_widths[rule_to_render_type (i)]);
+ width = MAX (width, params->line_widths[i]);
return width;
}
}
/* Maps a contiguous range of cells from a page to the underlying table along
- the horizpntal or vertical dimension. */
+ the horizontal or vertical dimension. */
struct map
{
int p0; /* First ordinate in the page. */
}
}
-/* Creates and returns a new render_page for rendering TABLE on a device
- described by PARAMS.
+/* Creates and returns a new render_page for rendering TABLE with the given
+ LOOK on a device described by PARAMS.
The new render_page will be suitable for rendering on a device whose page
size is PARAMS->size, but the caller is responsible for actually breaking it
up to fit on such a device, using the render_break abstraction. */
static struct render_page *
render_page_create (const struct render_params *params, struct table *table,
- int min_width)
+ int min_width, const struct pivot_table_look *look)
{
enum { MIN, MAX };
rules[axis][z] = measure_rule (params, table, axis, z);
}
+ int col_heading_width_range[2];
+ int row_heading_width_range[2];
+ for (int i = 0; i < 2; i++)
+ col_heading_width_range[i] = look->col_heading_width_range[i] * params->px_size;
+ for (int i = 0; i < 2; i++)
+ row_heading_width_range[i] = look->row_heading_width_range[i] * params->px_size;
+
/* Calculate minimum and maximum widths of cells that do not
span multiple columns. */
struct render_row *columns[2];
for (int i = 0; i < 2; i++)
- columns[i] = xcalloc (nc , sizeof *columns[i]);
+ columns[i] = xcalloc (nc, sizeof *columns[i]);
for (int y = 0; y < nr; y++)
for (int x = 0; x < nc;)
{
int w[2];
params->ops->measure_cell_width (params->aux, &cell,
&w[MIN], &w[MAX]);
+
+ if (params->px_size)
+ {
+ const int *wr = (x < table->h[H][0] ? row_heading_width_range
+ : y < table->h[V][0] ? col_heading_width_range
+ : NULL);
+ if (wr)
+ {
+ if (w[0] < wr[0])
+ {
+ w[0] = wr[0];
+ if (w[0] > w[1])
+ w[1] = w[0];
+ }
+ else if (w[1] > wr[1])
+ {
+ w[1] = wr[1];
+ if (w[1] < w[0])
+ w[0] = w[1];
+ }
+ }
+ }
+
for (int i = 0; i < 2; i++)
if (columns[i][x].unspanned < w[i])
columns[i][x].unspanned = w[i];
params->ops->measure_cell_width (params->aux, &cell,
&w[MIN], &w[MAX]);
for (int i = 0; i < 2; i++)
- distribute_spanned_width (w[i], &columns[i][cell.d[H][0]],
- rules[H], table_cell_colspan (&cell));
+ distribute_spanned_width (w[i],
+ &columns[i][cell.d[H][0]],
+ &rules[H][cell.d[H][0]],
+ table_cell_colspan (&cell));
}
x = cell.d[H][1];
}
{
int w = joined_width (page, H, cell.d[H][0], cell.d[H][1]);
int h = params->ops->measure_cell_height (params->aux, &cell, w);
- distribute_spanned_width (h, &rows[cell.d[V][0]], rules[V],
+ distribute_spanned_width (h,
+ &rows[cell.d[V][0]],
+ &rules[V][cell.d[V][0]],
table_cell_rowspan (&cell));
}
x = cell.d[H][1];
\f
/* Drawing render_pages. */
-/* This is like table_get_rule() except:
-
- - D is in terms of the page's rows and column rather than the underlying
- table's.
-
- - The result is in the form of a render_line_style. */
-static enum render_line_style
+/* This is like table_get_rule() except that D is in terms of the page's rows
+ and column rather than the underlying table's. */
+static struct table_border_style
get_rule (const struct render_page *page, enum table_axis axis,
- const int d_[TABLE_N_AXES], struct cell_color *color)
+ const int d_[TABLE_N_AXES])
{
int d[TABLE_N_AXES] = { d_[0] / 2, d_[1] / 2 };
int d2 = -1;
get_map (page, b, d[b], &m);
d[b] += m.t0 - m.p0;
- int r = table_get_rule (page->table, axis, d[H], d[V], color);
+ struct table_border_style border
+ = table_get_rule (page->table, axis, d[H], d[V]);
if (d2 >= 0)
{
d[a] = d2;
- int r2 = table_get_rule (page->table, axis, d[H], d[V], color);
- r = table_stroke_combine (r, r2);
+ struct table_border_style border2 = table_get_rule (page->table, axis,
+ d[H], d[V]);
+ border.stroke = table_stroke_combine (border.stroke, border2.stroke);
}
- return rule_to_render_type (r);
+ return border;
}
static bool
render_rule (const struct render_page *page, const int ofs[TABLE_N_AXES],
const int d[TABLE_N_AXES])
{
- enum render_line_style styles[TABLE_N_AXES][2];
- struct cell_color colors[TABLE_N_AXES][2];
+ const struct table_border_style none = { .stroke = TABLE_STROKE_NONE };
+ struct table_border_style styles[TABLE_N_AXES][2];
for (enum table_axis a = 0; a < TABLE_N_AXES; a++)
{
enum table_axis b = !a;
- styles[a][0] = styles[a][1] = RENDER_LINE_NONE;
-
if (!is_rule (d[a])
|| (page->is_edge_cutoff[a][0] && d[a] == 0)
|| (page->is_edge_cutoff[a][1] && d[a] == page->n[a] * 2))
- continue;
-
- if (is_rule (d[b]))
+ styles[a][0] = styles[a][1] = none;
+ else if (is_rule (d[b]))
{
if (d[b] > 0)
{
e[H] = d[H];
e[V] = d[V];
e[b]--;
- styles[a][0] = get_rule (page, a, e, &colors[a][0]);
+ styles[a][0] = get_rule (page, a, e);
}
+ else
+ styles[a][0] = none;
if (d[b] / 2 < page->n[b])
- styles[a][1] = get_rule (page, a, d, &colors[a][1]);
+ styles[a][1] = get_rule (page, a, d);
+ else
+ styles[a][1] = none;
}
else
- {
- styles[a][0] = styles[a][1] = get_rule (page, a, d, &colors[a][0]);
- colors[a][1] = colors[a][0];
- }
+ styles[a][0] = styles[a][1] = get_rule (page, a, d);
}
- if (styles[H][0] != RENDER_LINE_NONE || styles[H][1] != RENDER_LINE_NONE
- || styles[V][0] != RENDER_LINE_NONE || styles[V][1] != RENDER_LINE_NONE)
+ if (styles[H][0].stroke != TABLE_STROKE_NONE
+ || styles[H][1].stroke != TABLE_STROKE_NONE
+ || styles[V][0].stroke != TABLE_STROKE_NONE
+ || styles[V][1].stroke != TABLE_STROKE_NONE)
{
int bb[TABLE_N_AXES][2];
}
bb[V][0] = ofs[V] + page->cp[V][d[V]];
bb[V][1] = ofs[V] + page->cp[V][d[V] + 1];
- page->params->ops->draw_line (page->params->aux, bb, styles, colors);
+ page->params->ops->draw_line (page->params->aux, bb, styles);
}
}
render_cell (const struct render_page *page, const int ofs[TABLE_N_AXES],
const struct table_cell *cell)
{
+ const bool debugging = false;
+ if (debugging)
+ {
+ printf ("render ");
+ if (cell->d[H][0] + 1 == cell->d[H][1])
+ printf ("%d", cell->d[H][0]);
+ else
+ printf ("%d-%d", cell->d[H][0], cell->d[H][1] - 1);
+ printf (",");
+ if (cell->d[V][0] + 1 == cell->d[V][1])
+ printf ("%d", cell->d[V][0]);
+ else
+ printf ("%d-%d", cell->d[V][0], cell->d[V][1] - 1);
+
+ char *value = pivot_value_to_string (cell->value, NULL);
+ printf (": \"%s\"\n", value);
+ free (value);
+ }
+
int bb[TABLE_N_AXES][2];
int clip[TABLE_N_AXES][2];
static void
render_pager_add_table (struct render_pager *p, struct table *table,
- int min_width)
+ int min_width, const struct pivot_table_look *look)
{
if (table)
- p->pages[p->n_pages++] = render_page_create (p->params, table, min_width);
+ p->pages[p->n_pages++] = render_page_create (p->params, table, min_width,
+ look);
}
static void
/* Figure out the width of the body of the table. Use this to determine the
base scale. */
- struct render_page *body_page = render_page_create (params, body, 0);
+ struct render_page *body_page = render_page_create (params, body, 0, pt->look);
int body_width = table_width (body_page, H);
double scale = 1.0;
if (body_width > params->size[H])
/* Create the pager. */
struct render_pager *p = xmalloc (sizeof *p);
*p = (struct render_pager) { .params = params, .scale = scale };
- render_pager_add_table (p, title, body_width);
- render_pager_add_table (p, layers, body_width);
+ render_pager_add_table (p, title, body_width, pt->look);
+ render_pager_add_table (p, layers, body_width, pt->look);
p->pages[p->n_pages++] = body_page;
- render_pager_add_table (p, caption, 0);
- render_pager_add_table (p, footnotes, 0);
+ render_pager_add_table (p, caption, 0, pt->look);
+ render_pager_add_table (p, footnotes, 0, pt->look);
assert (p->n_pages <= sizeof p->pages / sizeof *p->pages);
/* If we're shrinking tables to fit the page length, then adjust the scale