{
struct table_item *table_item;
- table_item = table_item_create (table_from_string (TAB_LEFT, text),
+ table_item = table_item_create (table_from_string (TABLE_HALIGN_LEFT, text),
NULL, NULL);
ascii_output_table_item (a, table_item);
table_item_unref (table_item);
}
static void
-text_draw (struct ascii_driver *a, unsigned int options,
+text_draw (struct ascii_driver *a, enum table_halign halign, int options,
bool bold, bool underline,
int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2],
int y, const uint8_t *string, int n, size_t width)
if (y < y0 || y >= y1)
return;
- switch (options & TAB_HALIGN)
+ switch (table_halign_interpret (halign, options & TAB_NUMERIC))
{
- case TAB_LEFT:
+ case TABLE_HALIGN_LEFT:
x = bb[H][0];
break;
- case TAB_CENTER:
+ case TABLE_HALIGN_CENTER:
x = (bb[H][0] + bb[H][1] - width + 1) / 2;
break;
- case TAB_RIGHT:
+ case TABLE_HALIGN_RIGHT:
+ case TABLE_HALIGN_DECIMAL:
x = bb[H][1] - width;
break;
default:
width -= ofs - graph_ofs;
/* Draw text. */
- text_draw (a, cell->options, cell->style->bold, cell->style->underline,
+ text_draw (a, cell->style->cell_style.halign, cell->options,
+ cell->style->font_style.bold,
+ cell->style->font_style.underline,
bb, clip, y, line, graph_ofs, width);
/* If a new-line ended the line, just skip the new-line. Otherwise, skip
if (a->file == NULL && !ascii_open_page (a))
return;
- struct cell_style style = {
- .bold = bold,
- .underline = underline,
+ struct area_style style = {
+ .font_style.bold = bold,
+ .font_style.underline = underline,
};
struct table_cell cell = {
.options = TAB_LEFT,
}
}
+static int
+get_layout_height (PangoLayout *layout)
+{
+ int w, h;
+ pango_layout_get_size (layout, &w, &h);
+ return h;
+}
+
static int
xr_render_page_heading (cairo_t *cairo, const PangoFontDescription *font,
const struct page_heading *ph, int page_number,
pango_layout_set_markup (layout, markup, -1);
free (markup);
- pango_layout_set_alignment (layout,
- (pp->halign == TAB_RIGHT ? PANGO_ALIGN_RIGHT
- : pp->halign == TAB_LEFT ? PANGO_ALIGN_LEFT
- : PANGO_ALIGN_CENTER));
+ pango_layout_set_alignment (
+ layout,
+ (pp->halign == TABLE_HALIGN_LEFT ? PANGO_ALIGN_LEFT
+ : pp->halign == TABLE_HALIGN_CENTER ? PANGO_ALIGN_CENTER
+ : pp->halign == TABLE_HALIGN_MIXED ? PANGO_ALIGN_LEFT
+ : PANGO_ALIGN_RIGHT));
pango_layout_set_width (layout, xr_to_pango (width));
if (draw)
{
cairo_restore (cairo);
}
- int w, h;
- pango_layout_get_size (layout, &w, &h);
- y += pango_to_xr (h);
+ y += pango_to_xr (get_layout_height (layout));
}
g_object_unref (G_OBJECT (layout));
xr_layout_cell (xr, cell, bb, clip, min_width, &h, NULL);
if (*min_width > 0)
- *min_width += px_to_xr (cell->style->margin[H][0]
- + cell->style->margin[H][1]);
+ *min_width += px_to_xr (cell->style->cell_style.margin[H][0]
+ + cell->style->cell_style.margin[H][1]);
if (*max_width > 0)
- *max_width += px_to_xr (cell->style->margin[H][0]
- + cell->style->margin[H][1]);
+ *max_width += px_to_xr (cell->style->cell_style.margin[H][0]
+ + cell->style->cell_style.margin[H][1]);
}
static int
int w, h;
bb[H][0] = 0;
- bb[H][1] = width - px_to_xr (cell->style->margin[H][0]
- + cell->style->margin[H][1]);
+ bb[H][1] = width - px_to_xr (cell->style->cell_style.margin[H][0]
+ + cell->style->cell_style.margin[H][1]);
bb[V][0] = 0;
bb[V][1] = INT_MAX;
clip[H][0] = clip[H][1] = clip[V][0] = clip[V][1] = 0;
xr_layout_cell (xr, cell, bb, clip, &w, &h, NULL);
- h += px_to_xr (cell->style->margin[V][0] + cell->style->margin[V][1]);
+ h += px_to_xr (cell->style->cell_style.margin[V][0]
+ + cell->style->cell_style.margin[V][1]);
return h;
}
}
xr_clip (xr, bg_clip);
cairo_set_source_rgb (xr->cairo,
- cell->style->bg[color_idx].r / 255.,
- cell->style->bg[color_idx].g / 255.,
- cell->style->bg[color_idx].b / 255.);
+ cell->style->font_style.bg[color_idx].r / 255.,
+ cell->style->font_style.bg[color_idx].g / 255.,
+ cell->style->font_style.bg[color_idx].b / 255.);
fill_rectangle (xr,
bb[H][0] - spill[H][0],
bb[V][0] - spill[V][0],
cairo_save (xr->cairo);
cairo_set_source_rgb (xr->cairo,
- cell->style->fg[color_idx].r / 255.,
- cell->style->fg[color_idx].g / 255.,
- cell->style->fg[color_idx].b / 255.);
+ cell->style->font_style.fg[color_idx].r / 255.,
+ cell->style->font_style.fg[color_idx].g / 255.,
+ cell->style->font_style.fg[color_idx].b / 255.);
for (int axis = 0; axis < TABLE_N_AXES; axis++)
{
- bb[axis][0] += px_to_xr (cell->style->margin[axis][0]);
- bb[axis][1] -= px_to_xr (cell->style->margin[axis][1]);
+ bb[axis][0] += px_to_xr (cell->style->cell_style.margin[axis][0]);
+ bb[axis][1] -= px_to_xr (cell->style->cell_style.margin[axis][1]);
}
if (bb[H][0] < bb[H][1] && bb[V][0] < bb[V][1])
xr_layout_cell (xr, cell, bb, clip, &w, &h, &brk);
return -1;
bb[H][0] = 0;
- bb[H][1] = width - px_to_xr (cell->style->margin[H][0]
- + cell->style->margin[H][1]);
+ bb[H][1] = width - px_to_xr (cell->style->cell_style.margin[H][0]
+ + cell->style->cell_style.margin[H][1]);
if (bb[H][1] <= 0)
return 0;
bb[V][0] = 0;
- bb[V][1] = height - px_to_xr (cell->style->margin[V][0]
- + cell->style->margin[V][1]);
+ bb[V][1] = height - px_to_xr (cell->style->cell_style.margin[V][0]
+ + cell->style->cell_style.margin[V][1]);
clip[H][0] = clip[H][1] = clip[V][0] = clip[V][1] = 0;
xr_layout_cell (xr, cell, bb, clip, &w, &h, &brk);
return brk;
int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2],
int *widthp, int *brk)
{
- const struct cell_style *style = cell->style;
+ const struct font_style *font_style = &cell->style->font_style;
+ const struct cell_style *cell_style = &cell->style->cell_style;
unsigned int options = cell->options;
enum table_axis X = options & TAB_ROTATE ? V : H;
: options & TAB_EMPH ? &xr->fonts[XR_FONT_EMPHASIS]
: &xr->fonts[XR_FONT_PROPORTIONAL]);
struct xr_font local_font;
- if (cell->style->typeface)
+ if (font_style->typeface)
{
PangoFontDescription *desc = parse_font (
- style->typeface,
- style->size ? style->size * 1000 * 72 / 128 : 10000,
- style->bold, style->italic);
+ font_style->typeface,
+ font_style->size ? font_style->size * 1000 * 72 / 128 : 10000,
+ font_style->bold, font_style->italic);
if (desc)
{
PangoLayout *layout = pango_cairo_create_layout (xr->cairo);
}
}
- int footnote_adjustment;
- if (cell->n_footnotes == 0)
- footnote_adjustment = 0;
- else if (cell->n_footnotes == 1 && (options & TAB_HALIGN) == TAB_RIGHT)
+ const char *text = cell->text;
+ enum table_halign halign = table_halign_interpret (
+ cell_style->halign, cell->options & TAB_NUMERIC);
+ if (cell_style->halign == TABLE_HALIGN_DECIMAL && !(options & TAB_ROTATE))
{
- const char *marker = cell->footnotes[0]->marker;
- pango_layout_set_text (font->layout, marker, strlen (marker));
+ int margin_adjustment = -px_to_xr (cell_style->decimal_offset);
- PangoAttrList *attrs = pango_attr_list_new ();
- pango_attr_list_insert (attrs, pango_attr_rise_new (7000));
- pango_layout_set_attributes (font->layout, attrs);
- pango_attr_list_unref (attrs);
-
- int w = get_layout_dimension (font->layout, X);
- int right_margin = px_to_xr (cell->style->margin[X][R]);
- footnote_adjustment = MIN (w, right_margin);
+ const char *decimal = strrchr (text, cell_style->decimal_char);
+ if (decimal)
+ {
+ pango_layout_set_text (font->layout, decimal, strlen (decimal));
+ pango_layout_set_width (font->layout, -1);
+ margin_adjustment += get_layout_dimension (font->layout, H);
+ }
- pango_layout_set_attributes (font->layout, NULL);
+ if (margin_adjustment < 0)
+ bb[H][1] += margin_adjustment;
}
- else
- footnote_adjustment = px_to_xr (cell->style->margin[X][R]);
struct string tmp = DS_EMPTY_INITIALIZER;
- const char *text = cell->text;
/* Deal with an oddity of the Unicode line-breaking algorithm (or perhaps in
Pango's implementation of it): it will break after a period or a comma
}
}
- if (footnote_adjustment)
+ if (cell->n_footnotes)
{
+ int footnote_adjustment;
+ if (cell->n_footnotes == 1 && halign == TABLE_HALIGN_RIGHT)
+ {
+ const char *marker = cell->footnotes[0]->marker;
+ pango_layout_set_text (font->layout, marker, strlen (marker));
+
+ PangoAttrList *attrs = pango_attr_list_new ();
+ pango_attr_list_insert (attrs, pango_attr_rise_new (7000));
+ pango_layout_set_attributes (font->layout, attrs);
+ pango_attr_list_unref (attrs);
+
+ int w = get_layout_dimension (font->layout, X);
+ int right_margin = px_to_xr (cell_style->margin[X][R]);
+ footnote_adjustment = MIN (w, right_margin);
+
+ pango_layout_set_attributes (font->layout, NULL);
+ }
+ else
+ footnote_adjustment = px_to_xr (cell_style->margin[X][R]);
+
if (R)
bb[X][R] += footnote_adjustment;
else
pango_layout_set_text (font->layout, ds_cstr (&tmp), ds_length (&tmp));
PangoAttrList *attrs = pango_attr_list_new ();
- if (style->underline)
+ if (font_style->underline)
pango_attr_list_insert (attrs, pango_attr_underline_new (
PANGO_UNDERLINE_SINGLE));
add_attr_with_start (attrs, pango_attr_rise_new (7000), initial_length);
else
pango_layout_set_text (font->layout, content, -1);
- if (style->underline)
+ if (font_style->underline)
{
PangoAttrList *attrs = pango_attr_list_new ();
pango_attr_list_insert (attrs, pango_attr_underline_new (
}
ds_destroy (&tmp);
- pango_layout_set_alignment (
- font->layout,
- ((options & TAB_HALIGN) == TAB_RIGHT ? PANGO_ALIGN_RIGHT
- : (options & TAB_HALIGN) == TAB_LEFT ? PANGO_ALIGN_LEFT
- : PANGO_ALIGN_CENTER));
+ pango_layout_set_alignment (font->layout,
+ (halign == TABLE_HALIGN_RIGHT ? PANGO_ALIGN_RIGHT
+ : halign == TABLE_HALIGN_LEFT ? PANGO_ALIGN_LEFT
+ : PANGO_ALIGN_CENTER));
pango_layout_set_width (
font->layout,
bb[X][1] == INT_MAX ? -1 : xr_to_pango (bb[X][1] - bb[X][0]));
struct table_item *table_item;
struct xr_rendering *r;
- table_item = table_item_create (table_from_string (TAB_LEFT, text),
+ table_item = table_item_create (table_from_string (TABLE_HALIGN_LEFT, text),
NULL, NULL);
r = xr_rendering_create (xr, &table_item->output_item, cr);
table_item_unref (table_item);
tag = is_header ? "TH" : "TD";
fprintf (html->file, " <%s", tag);
- int halign = cell.options & TAB_HALIGN;
- if (halign != TAB_LEFT)
- fprintf (html->file, " ALIGN=\"%s\"",
- halign == TAB_RIGHT ? "RIGHT" : "CENTER");
+ enum table_halign halign = table_halign_interpret (
+ cell.style->cell_style.halign, cell.options & TAB_NUMERIC);
+ if (halign != TABLE_HALIGN_LEFT)
+ {
+ fprintf (html->file, " ALIGN=\"%s\"",
+ (halign == TABLE_HALIGN_RIGHT ? "RIGHT"
+ : halign == TABLE_HALIGN_CENTER ? "CENTER"
+ : "CHAR"));
+ if (cell.style->cell_style.decimal_char)
+ fprintf (html->file, " CHAR=\"%c\"",
+ cell.style->cell_style.decimal_char);
+ }
- int valign = cell.options & TAB_VALIGN;
- if (valign != TAB_TOP)
+ if (cell.style->cell_style.valign != TABLE_VALIGN_TOP)
fprintf (html->file, " ALIGN=\"%s\"",
- valign == TAB_BOTTOM ? "BOTTOM" : "MIDDLE");
+ (cell.style->cell_style.valign == TABLE_VALIGN_BOTTOM
+ ? "BOTTOM" : "MIDDLE"));
colspan = table_cell_colspan (&cell);
if (colspan > 1)
/* Calculate maximum width of the rules that are present. */
int width = 0;
- for (size_t i = 0; i < N_LINES; i++)
+ for (size_t i = 0; i < TABLE_N_STROKES; i++)
if (rules & (1u << i))
width = MAX (width, params->line_widths[a][rule_to_render_type (i)]);
return width;
bb[V][0] = clip[V][0] = ofs[V] + page->cp[V][cell->d[V][0] * 2 + 1];
bb[V][1] = clip[V][1] = ofs[V] + page->cp[V][cell->d[V][1] * 2];
- int valign = cell->options & TAB_VALIGN;
- if (valign != TAB_TOP)
+ enum table_valign valign = cell->style->cell_style.valign;
+ if (valign != TABLE_VALIGN_TOP)
{
int height = page->params->measure_cell_height (
page->params->aux, cell, bb[H][1] - bb[H][0]);
int extra = bb[V][1] - bb[V][0] - height;
if (extra > 0)
{
- if (valign == TAB_MIDDLE)
+ if (valign == TABLE_VALIGN_CENTER)
extra /= 2;
bb[V][0] += extra;
}
return;
struct tab_table *tab = tab_create (1, 1);
- tab_text (tab, 0, 0, t->halign, t->content);
+ tab_text (tab, 0, 0, 0, t->content);
for (size_t i = 0; i < t->n_footnotes; i++)
tab_add_footnote (tab, 0, 0, t->footnotes[i]);
if (t->style)
- tab->styles[0] = cell_style_clone (tab->container, t->style);
+ tab->styles[0] = area_style_clone (tab->container, t->style);
render_pager_add_table (p, &tab->table, min_width);
}
size_t n_footnotes;
const struct footnote **footnotes;
- const struct cell_style *style;
+ const struct area_style *style;
};
static const struct table_class tab_table_class;
struct footnote *
tab_create_footnote (struct tab_table *table, size_t idx, const char *content,
- const char *marker, struct cell_style *style)
+ const char *marker, struct area_style *style)
{
struct footnote *f = pool_alloc (table->container, sizeof *f);
f->idx = idx;
void
tab_add_style (struct tab_table *table, int x, int y,
- const struct cell_style *style)
+ const struct area_style *style)
{
int index = x + y * table->cf;
unsigned short opt = table->ct[index];
cell->destructor = NULL;
int style_idx = (opt & TAB_STYLE_MASK) >> TAB_STYLE_SHIFT;
- const struct cell_style *style = t->styles[style_idx];
+ const struct area_style *style = t->styles[style_idx];
if (style)
cell->style = style;
+ else
+ {
+ static const struct area_style styles[3][3] = {
+#define S(H,V) [H][V] = { AREA_STYLE_INITIALIZER__, \
+ .cell_style.halign = H, \
+ .cell_style.valign = V }
+ S(TABLE_HALIGN_LEFT, TABLE_VALIGN_TOP),
+ S(TABLE_HALIGN_LEFT, TABLE_VALIGN_CENTER),
+ S(TABLE_HALIGN_LEFT, TABLE_VALIGN_BOTTOM),
+ S(TABLE_HALIGN_CENTER, TABLE_VALIGN_TOP),
+ S(TABLE_HALIGN_CENTER, TABLE_VALIGN_CENTER),
+ S(TABLE_HALIGN_CENTER, TABLE_VALIGN_BOTTOM),
+ S(TABLE_HALIGN_RIGHT, TABLE_VALIGN_TOP),
+ S(TABLE_HALIGN_RIGHT, TABLE_VALIGN_CENTER),
+ S(TABLE_HALIGN_RIGHT, TABLE_VALIGN_BOTTOM),
+ };
+
+ enum table_halign halign
+ = ((opt & TAB_HALIGN) == TAB_LEFT ? TABLE_HALIGN_LEFT
+ : (opt & TAB_HALIGN) == TAB_CENTER ? TABLE_HALIGN_CENTER
+ : TABLE_HALIGN_RIGHT);
+ enum table_valign valign
+ = ((opt & TAB_VALIGN) == TAB_TOP ? TABLE_VALIGN_TOP
+ : (opt & TAB_VALIGN) == TAB_CENTER ? TABLE_VALIGN_CENTER
+ : TABLE_VALIGN_BOTTOM);
+
+ cell->style = &styles[halign][valign];
+ }
if (opt & TAB_JOIN)
{
n_RC
};
-#define TAB_STYLE_MASK (7u << (TAB_FIRST_AVAILABLE + 3))
-#define TAB_STYLE_SHIFT (TAB_FIRST_AVAILABLE + 3)
+#define TAB_STYLE_MASK (7u << (TAB_FIRST_AVAILABLE + 1))
+#define TAB_STYLE_SHIFT (TAB_FIRST_AVAILABLE + 1)
+
+enum
+ {
+ /* Horizontal alignment of cell contents. */
+ TAB_RIGHT = 0 << (TAB_FIRST_AVAILABLE + 2),
+ TAB_LEFT = 1 << (TAB_FIRST_AVAILABLE + 2),
+ TAB_CENTER = 2 << (TAB_FIRST_AVAILABLE + 2),
+ TAB_HALIGN = 3 << (TAB_FIRST_AVAILABLE + 2), /* Alignment mask. */
+
+ /* Vertical alignment of cell contents. */
+ TAB_TOP = 0 << (TAB_FIRST_AVAILABLE + 4),
+ TAB_MIDDLE = 1 << (TAB_FIRST_AVAILABLE + 4),
+ TAB_BOTTOM = 2 << (TAB_FIRST_AVAILABLE + 4),
+ TAB_VALIGN = 3 << (TAB_FIRST_AVAILABLE + 4), /* Alignment mask. */
+ };
/* Rule masks. */
#define TAB_RULE_TYPE_MASK 7
points to a struct tab_joined_cell. */
void **cc; /* Cell contents; void *[nr][nc]. */
unsigned short *ct; /* Cell types; unsigned short[nr][nc]. */
- struct cell_style *styles[8];
+ struct area_style *styles[8];
/* Rules. */
unsigned char *rh; /* Horiz rules; unsigned char[nr+1][nc]. */
struct footnote *tab_create_footnote (struct tab_table *, size_t idx,
const char *content, const char *marker,
- struct cell_style *);
+ struct area_style *);
void tab_add_footnote (struct tab_table *, int x, int y,
const struct footnote *);
void tab_add_style (struct tab_table *, int x, int y,
- const struct cell_style *);
+ const struct area_style *);
bool tab_cell_is_empty (const struct tab_table *, int c, int r);
struct ccase *c;
char *s;
+ static const struct area_style style = {
+ AREA_STYLE_INITIALIZER__,
+ .cell_style.halign = TABLE_HALIGN_RIGHT
+ };
+
cell->d[TABLE_HORZ][0] = x;
cell->d[TABLE_HORZ][1] = x + 1;
cell->d[TABLE_VERT][0] = y;
cell->d[TABLE_VERT][1] = y + 1;
- cell->options = TAB_RIGHT;
+ cell->style = &style;
+ cell->options = 0;
cell->n_footnotes = 0;
if (tc->heading != NULL)
{
return NULL;
struct table_item_text *text = xmalloc (sizeof *text);
- *text = (struct table_item_text) { .content = xstrdup (content),
- .halign = TAB_LEFT };
+ *text = (struct table_item_text) { .content = xstrdup (content) };
return text;
}
.footnotes = xmemdup (old->footnotes,
old->n_footnotes * sizeof *old->footnotes),
.n_footnotes = old->n_footnotes,
- .style = cell_style_clone (NULL, old->style),
- .halign = old->halign,
+ .style = area_style_clone (NULL, old->style),
};
return new;
}
{
free (text->content);
free (text->footnotes);
- cell_style_free (text->style);
+ area_style_free (text->style);
free (text);
}
}
#include "libpspp/compiler.h"
#include "output/output-item.h"
+#include "output/table.h"
/* Title or caption in a table item. */
struct table_item_text
char *content;
const struct footnote **footnotes;
size_t n_footnotes;
- int halign; /* TAB_*. */
- struct cell_style *style;
+ struct area_style *style;
};
struct table_item_text *table_item_text_create (const char *);
struct pool;
struct string;
+enum table_halign table_halign_interpret (enum table_halign, bool numeric);
+
struct footnote
{
size_t idx;
char *content;
char *marker;
- struct cell_style *style;
- };
-
-struct cell_color
- {
- uint8_t r, g, b;
+ struct area_style *style;
};
-#define CELL_COLOR(r, g, b) (struct cell_color) { r, g, b }
-#define CELL_COLOR_BLACK CELL_COLOR (0, 0, 0)
-#define CELL_COLOR_WHITE CELL_COLOR (255, 255, 255)
-
-static inline bool
-cell_color_equal (const struct cell_color *a, const struct cell_color *b)
-{
- return a->r == b->r && a->g == b->g && a->b == b->b;
-}
-
-struct cell_style
- {
- struct cell_color fg[2], bg[2];
- int margin[TABLE_N_AXES][2];
- char *typeface;
- int size;
- bool bold, italic, underline;
- };
-
-#define CELL_STYLE_INITIALIZER \
- { \
- .fg = { [0] = CELL_COLOR_BLACK, [1] = CELL_COLOR_BLACK}, \
- .bg = { [0] = CELL_COLOR_WHITE, [1] = CELL_COLOR_WHITE}, \
- .margin = { [TABLE_HORZ][0] = 8, [TABLE_HORZ][1] = 11, \
- [TABLE_VERT][0] = 1, [TABLE_VERT][1] = 1 }, \
- .typeface = NULL, \
- .size = 0, \
- .bold = false, \
- .italic = false, \
- .underline = false, \
- }
-
-struct cell_style *cell_style_clone (struct pool *, const struct cell_style *);
-void cell_style_free (struct cell_style *);
-
/* A cell in a table. */
struct table_cell
{
const struct footnote **footnotes;
size_t n_footnotes;
- const struct cell_style *style;
+ const struct area_style *style;
/* Called to free the cell's data, if nonnull. */
void (*destructor) (void *destructor_aux);
#include "output/table-provider.h"
#include <assert.h>
+#include <inttypes.h>
#include <stdlib.h>
+#include "libpspp/assertion.h"
#include "libpspp/cast.h"
#include "libpspp/compiler.h"
#include "libpspp/pool.h"
table->n[TABLE_VERT] = nr;
}
\f
-struct cell_style *
-cell_style_clone (struct pool *pool, const struct cell_style *old)
+struct area_style *
+area_style_clone (struct pool *pool, const struct area_style *old)
{
- struct cell_style *new = pool_malloc (pool, sizeof *new);
+ struct area_style *new = pool_malloc (pool, sizeof *new);
*new = *old;
- if (new->typeface)
- new->typeface = pool_strdup (pool, new->typeface);
+ if (new->font_style.typeface)
+ new->font_style.typeface = pool_strdup (pool, new->font_style.typeface);
return new;
}
void
-cell_style_free (struct cell_style *style)
+area_style_free (struct area_style *style)
{
if (style)
{
- free (style->typeface);
+ free (style->font_style.typeface);
free (style);
}
}
assert (x >= 0 && x < table->n[TABLE_HORZ]);
assert (y >= 0 && y < table->n[TABLE_VERT]);
- static const struct cell_style default_style = CELL_STYLE_INITIALIZER;
+ static const struct area_style default_style = AREA_STYLE_INITIALIZER;
cell->style = &default_style;
table->klass->get_cell (table, x, y, cell);
{
assert (x >= 0 && x < table->n[TABLE_HORZ] + (axis == TABLE_HORZ));
assert (y >= 0 && y < table->n[TABLE_VERT] + (axis == TABLE_VERT));
- *color = CELL_COLOR_BLACK;
+ *color = (struct cell_color) CELL_COLOR_BLACK;
return table->klass->get_rule (table, axis, x, y, color);
}
{
struct table table;
char *string;
- unsigned int options;
+ enum table_halign halign;
};
static const struct table_class table_string_class;
/* Returns a table that contains a single cell, whose contents are S with
options OPTIONS (a combination of TAB_* values). */
struct table *
-table_from_string (unsigned int options, const char *s)
+table_from_string (enum table_halign halign, const char *s)
{
struct table_string *ts = xmalloc (sizeof *ts);
table_init (&ts->table, &table_string_class);
ts->table.n[TABLE_HORZ] = ts->table.n[TABLE_VERT] = 1;
ts->string = xstrdup (s);
- ts->options = options;
+ ts->halign = halign;
return &ts->table;
}
table_string_get_cell (const struct table *ts_, int x UNUSED, int y UNUSED,
struct table_cell *cell)
{
+ static const struct area_style styles[] = {
+#define S(H) [H] = { AREA_STYLE_INITIALIZER__, .cell_style.halign = H }
+ S(TABLE_HALIGN_LEFT),
+ S(TABLE_HALIGN_CENTER),
+ S(TABLE_HALIGN_RIGHT),
+ S(TABLE_HALIGN_MIXED),
+ S(TABLE_HALIGN_DECIMAL),
+ };
struct table_string *ts = table_string_cast (ts_);
cell->d[TABLE_HORZ][0] = 0;
cell->d[TABLE_HORZ][1] = 1;
cell->d[TABLE_VERT][0] = 0;
cell->d[TABLE_VERT][1] = 1;
- cell->options = ts->options;
+ cell->options = 0;
+ cell->style = &styles[table_halign_interpret (ts->halign, false)];
cell->text = ts->string;
cell->n_footnotes = 0;
cell->destructor = NULL;
NULL, /* paste */
NULL, /* select */
};
+\f
+const char *
+table_halign_to_string (enum table_halign halign)
+{
+ switch (halign)
+ {
+ case TABLE_HALIGN_LEFT: return "left";
+ case TABLE_HALIGN_CENTER: return "center";
+ case TABLE_HALIGN_RIGHT: return "right";
+ case TABLE_HALIGN_DECIMAL: return "decimal";
+ case TABLE_HALIGN_MIXED: return "mixed";
+ default: return "**error**";
+ }
+}
+
+const char *
+table_valign_to_string (enum table_valign valign)
+{
+ switch (valign)
+ {
+ case TABLE_VALIGN_TOP: return "top";
+ case TABLE_VALIGN_CENTER: return "center";
+ case TABLE_VALIGN_BOTTOM: return "bottom";
+ default: return "**error**";
+ }
+}
+
+enum table_halign
+table_halign_interpret (enum table_halign halign, bool numeric)
+{
+ switch (halign)
+ {
+ case TABLE_HALIGN_LEFT:
+ case TABLE_HALIGN_CENTER:
+ case TABLE_HALIGN_RIGHT:
+ return halign;
+
+ case TABLE_HALIGN_MIXED:
+ return numeric ? TABLE_HALIGN_RIGHT : TABLE_HALIGN_LEFT;
+
+ case TABLE_HALIGN_DECIMAL:
+ return TABLE_HALIGN_DECIMAL;
+
+ default:
+ NOT_REACHED ();
+ }
+}
+
+void
+font_style_copy (struct font_style *dst, const struct font_style *src)
+{
+ *dst = *src;
+ if (dst->typeface)
+ dst->typeface = xstrdup (dst->typeface);
+}
+
+void
+font_style_uninit (struct font_style *font)
+{
+ if (font)
+ free (font->typeface);
+}
+
+void
+area_style_copy (struct area_style *dst, const struct area_style *src)
+{
+ font_style_copy (&dst->font_style, &src->font_style);
+ dst->cell_style = src->cell_style;
+}
+
+void
+area_style_uninit (struct area_style *area)
+{
+ if (area)
+ font_style_uninit (&area->font_style);
+}
+
+const char *
+table_stroke_to_string (enum table_stroke stroke)
+{
+ switch (stroke)
+ {
+ case TABLE_STROKE_NONE: return "none";
+ case TABLE_STROKE_SOLID: return "solid";
+ case TABLE_STROKE_DASHED: return "dashed";
+ case TABLE_STROKE_THICK: return "thick";
+ case TABLE_STROKE_THIN: return "thin";
+ case TABLE_STROKE_DOUBLE: return "double";
+ default:
+ return "**error**";
+ }
+}
+
+void
+cell_color_dump (const struct cell_color *c)
+{
+ if (c->alpha != 255)
+ printf ("rgba(%d, %d, %d, %d)", c->r, c->g, c->b, c->alpha);
+ else
+ printf ("#%02"PRIx8"%02"PRIx8"%02"PRIx8, c->r, c->g, c->b);
+}
+
+void
+font_style_dump (const struct font_style *f)
+{
+ printf ("%s %dpx ", f->typeface, f->size);
+ cell_color_dump (&f->fg[0]);
+ putchar ('/');
+ cell_color_dump (&f->bg[0]);
+ if (!cell_color_equal (&f->fg[0], &f->fg[1])
+ || !cell_color_equal (&f->bg[0], &f->bg[1]))
+ {
+ printf (" alt=");
+ cell_color_dump (&f->fg[1]);
+ putchar ('/');
+ cell_color_dump (&f->bg[1]);
+ }
+ if (f->bold)
+ fputs (" bold", stdout);
+ if (f->italic)
+ fputs (" italic", stdout);
+ if (f->underline)
+ fputs (" underline", stdout);
+}
+
+void
+cell_style_dump (const struct cell_style *c)
+{
+ fputs (table_halign_to_string (c->halign), stdout);
+ if (c->halign == TABLE_HALIGN_DECIMAL)
+ printf ("(%.2gpx)", c->decimal_offset);
+ printf (" %s", table_valign_to_string (c->valign));
+ printf (" %d,%d,%d,%dpx",
+ c->margin[TABLE_HORZ][0], c->margin[TABLE_HORZ][1],
+ c->margin[TABLE_VERT][0], c->margin[TABLE_VERT][1]);
+}
table-item.h) for that purpose. */
#include <stdbool.h>
+#include <stdint.h>
#include <stddef.h>
struct casereader;
struct fmt_spec;
+struct pool;
struct table_item;
struct variable;
-/* Properties of a table cell. */
-enum
+/* A table axis.
+
+ Many table-related declarations use 2-element arrays in place of "x" and "y"
+ variables. This reduces code duplication significantly, because much table
+ code treats rows and columns the same way.
+
+ A lot of code that uses these enumerations assumes that the two values are 0
+ and 1, so don't change them to other values. */
+enum table_axis
{
- TAB_NONE = 0,
+ TABLE_HORZ,
+ TABLE_VERT,
+ TABLE_N_AXES
+ };
+
+struct cell_color
+ {
+ uint8_t alpha, r, g, b;
+ };
+
+#define CELL_COLOR(r, g, b) (struct cell_color) { 255, r, g, b }
+#define CELL_COLOR_BLACK CELL_COLOR (0, 0, 0)
+#define CELL_COLOR_WHITE CELL_COLOR (255, 255, 255)
+
+static inline bool
+cell_color_equal (const struct cell_color *a, const struct cell_color *b)
+{
+ return a->alpha == b->alpha && a->r == b->r && a->g == b->g && a->b == b->b;
+}
+
+void cell_color_dump (const struct cell_color *);
+
+enum table_stroke
+ {
+ TABLE_STROKE_NONE,
+ TABLE_STROKE_SOLID,
+ TABLE_STROKE_DASHED,
+ TABLE_STROKE_THICK,
+ TABLE_STROKE_THIN,
+ TABLE_STROKE_DOUBLE,
+ TABLE_N_STROKES,
+ };
+
+const char *table_stroke_to_string (enum table_stroke);
+
+struct table_border_style
+ {
+ enum table_stroke stroke;
+ struct cell_color color;
+ };
+
+#define TABLE_BORDER_STYLE_INITIALIZER { TABLE_STROKE_SOLID, CELL_COLOR_BLACK }
+
+enum table_halign
+ {
+ TABLE_HALIGN_RIGHT,
+ TABLE_HALIGN_LEFT,
+ TABLE_HALIGN_CENTER,
+ TABLE_HALIGN_MIXED,
+ TABLE_HALIGN_DECIMAL
+ };
+
+const char *table_halign_to_string (enum table_halign);
- /* Horizontal alignment of cell contents. */
- TAB_RIGHT = 0 << 0,
- TAB_LEFT = 1 << 0,
- TAB_CENTER = 2 << 0,
- TAB_HALIGN = 3 << 0, /* Alignment mask. */
+enum table_valign
+ {
+ TABLE_VALIGN_TOP,
+ TABLE_VALIGN_CENTER,
+ TABLE_VALIGN_BOTTOM,
+ };
+
+const char *table_valign_to_string (enum table_valign);
+
+struct cell_style
+ {
+ enum table_halign halign;
+ enum table_valign valign;
+ double decimal_offset; /* In 1/96" units. */
+ char decimal_char; /* Either '.' or ','. */
+ int margin[TABLE_N_AXES][2]; /* In 1/96" units. */
+ };
+
+#define CELL_STYLE_INITIALIZER { CELL_STYLE_INITIALIZER__ }
+#define CELL_STYLE_INITIALIZER__ \
+ .margin = { [TABLE_HORZ][0] = 8, [TABLE_HORZ][1] = 11, \
+ [TABLE_VERT][0] = 1, [TABLE_VERT][1] = 1 }
+
+void cell_style_dump (const struct cell_style *);
+
+struct font_style
+ {
+ bool bold, italic, underline, markup;
+ struct cell_color fg[2], bg[2];
+ char *typeface;
+ int size;
+ };
+
+#define FONT_STYLE_INITIALIZER { FONT_STYLE_INITIALIZER__ }
+#define FONT_STYLE_INITIALIZER__ \
+ .fg = { [0] = CELL_COLOR_BLACK, [1] = CELL_COLOR_BLACK}, \
+ .bg = { [0] = CELL_COLOR_WHITE, [1] = CELL_COLOR_WHITE},
- /* Vertical alignment of cell contents. */
- TAB_TOP = 0 << 2,
- TAB_MIDDLE = 1 << 2,
- TAB_BOTTOM = 2 << 2,
- TAB_VALIGN = 3 << 2, /* Alignment mask. */
+void font_style_copy (struct font_style *, const struct font_style *);
+void font_style_uninit (struct font_style *);
+void font_style_dump (const struct font_style *);
- /* These flags may be combined with any alignment. */
- TAB_EMPH = 1 << 4, /* Emphasize cell contents. */
- TAB_FIX = 1 << 5, /* Use fixed font. */
- TAB_MARKUP = 1 << 6, /* Text contains Pango markup. */
- TAB_ROTATE = 1 << 7, /* Rotate cell contents 90 degrees. */
+struct area_style
+ {
+ struct cell_style cell_style;
+ struct font_style font_style;
+ };
+
+#define AREA_STYLE_INITIALIZER { AREA_STYLE_INITIALIZER__ }
+#define AREA_STYLE_INITIALIZER__ \
+ .cell_style = CELL_STYLE_INITIALIZER, \
+ .font_style = FONT_STYLE_INITIALIZER
+
+struct area_style *area_style_clone (struct pool *, const struct area_style *);
+void area_style_copy (struct area_style *, const struct area_style *);
+void area_style_uninit (struct area_style *);
+void area_style_free (struct area_style *);
+
+/* Properties of a table cell. */
+enum
+ {
+ TAB_NONE = 0,
+ TAB_EMPH = 1 << 0, /* Emphasize cell contents. */
+ TAB_FIX = 1 << 1, /* Use fixed font. */
+ TAB_MARKUP = 1 << 2, /* Text contains Pango markup. */
+ TAB_NUMERIC = 1 << 3, /* Cell contents are numeric. */
+ TAB_ROTATE = 1 << 4, /* Rotate cell contents 90 degrees. */
/* Bits with values (1 << TAB_FIRST_AVAILABLE) and higher are
not used, so they are available for subclasses to use as
they wish. */
- TAB_FIRST_AVAILABLE = 8
+ TAB_FIRST_AVAILABLE = 5
};
/* Styles for the rules around table cells. */
enum
{
- TAL_NONE, /* No spacing. */
+ TAL_NONE = TABLE_STROKE_NONE,
#define TAL_0 TAL_NONE
- TAL_SOLID,
+ TAL_SOLID = TABLE_STROKE_SOLID,
#define TAL_1 TAL_SOLID
- TAL_DASHED,
- TAL_THICK,
- TAL_THIN,
- TAL_DOUBLE,
+ TAL_DASHED = TABLE_STROKE_DASHED,
+ TAL_THICK = TABLE_STROKE_THICK,
+ TAL_THIN = TABLE_STROKE_THIN,
+ TAL_DOUBLE = TABLE_STROKE_DOUBLE,
#define TAL_2 TAL_DOUBLE
- N_LINES
};
/* Given line styles A and B (each one of the TAL_* enumeration constants
return a > b ? a : b;
}
-/* A table axis.
-
- Many table-related declarations use 2-element arrays in place of "x" and "y"
- variables. This reduces code duplication significantly, because much table
- code has treat rows and columns the same way.
-
- A lot of code that uses these enumerations assumes that the two values are 0
- and 1, so don't change them to other values. */
-enum table_axis
- {
- TABLE_HORZ,
- TABLE_VERT,
- TABLE_N_AXES
- };
-
/* A table. */
struct table
{
/* Table classes. */
/* Simple kinds of tables. */
-struct table *table_from_string (unsigned int options, const char *);
-struct table *table_from_string_span (unsigned int options, const char *,
- int colspan, int rowspan);
+struct table *table_from_string (enum table_halign, const char *);
struct table *table_from_variables (unsigned int options,
struct variable **, size_t);
struct table *table_from_casereader (const struct casereader *,
{
struct tab_table *tab = tab_create (1, 1);
- struct cell_style *style = pool_alloc (tab->container, sizeof *style);
- *style = (struct cell_style) CELL_STYLE_INITIALIZER;
+ struct area_style *style = pool_alloc (tab->container, sizeof *style);
+ *style = (struct area_style) AREA_STYLE_INITIALIZER;
+ struct font_style *font_style = &style->font_style;
if (text_item->typeface)
- style->typeface = pool_strdup (tab->container, text_item->typeface);
- style->size = text_item->size;
- style->bold = text_item->bold;
- style->italic = text_item->italic;
- style->underline = text_item->underline;
+ font_style->typeface = pool_strdup (tab->container, text_item->typeface);
+ font_style->size = text_item->size;
+ font_style->bold = text_item->bold;
+ font_style->italic = text_item->italic;
+ font_style->underline = text_item->underline;
+ font_style->markup = text_item->markup;
tab->styles[0] = style;
int opts = TAB_LEFT;
struct output_item output_item;
char *text; /* The content. */
enum text_item_type type; /* Type. */
+
+ bool bold, italic, underline, markup;
char *typeface;
int size;
- bool bold, italic, underline, markup;
};
struct text_item *text_item_create (enum text_item_type, const char *text);