You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
gnucash/lib/goffice/split/style-border.c

862 lines
24 KiB

/* vim: set sw=8: */
/*
* border.c: Managing drawing and printing cell borders
*
* Copyright (C) 1999-2001 Jody Goldberg (jody@gnome.org)
*
* This program 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 of the
* License, or (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include <config.h>
#include "gnumeric.h"
#include "style-border.h"
#include "style-color.h"
#include "style.h"
#include "mstyle.h"
//#include "sheet-style.h"
//#include "sheet.h"
struct LineDotPattern {
const gint elements;
const gint8 *const pattern;
const double *const pattern_d;
};
static const gint8 dashed_pattern[] = { 3, 1 };
static const double dashed_pattern_d[] = { 3., 1. };
static const struct LineDotPattern dashed_line =
{ sizeof (dashed_pattern), dashed_pattern, dashed_pattern_d };
static const gint8 med_dashed_pattern[] = { 9, 3 };
static const double med_dashed_pattern_d[] = { 9., 3. };
static const struct LineDotPattern med_dashed_line =
{ sizeof (med_dashed_pattern), med_dashed_pattern, med_dashed_pattern_d };
static const gint8 dotted_pattern[] = { 2, 2 };
static const double dotted_pattern_d[] = { 2., 2. };
static const struct LineDotPattern dotted_line =
{ sizeof (dotted_pattern), dotted_pattern, dotted_pattern_d };
static const gint8 hair_pattern[] = { 1, 1 };
static const double hair_pattern_d[] = { 1., 1. };
static const struct LineDotPattern hair_line =
{ sizeof (hair_pattern), hair_pattern, hair_pattern_d };
static const gint8 dash_dot_pattern[] = { 8, 3, 3, 3 };
static const double dash_dot_pattern_d[] = { 8., 3., 3., 3. };
static const struct LineDotPattern dash_dot_line =
{ sizeof (dash_dot_pattern), dash_dot_pattern, dash_dot_pattern_d };
static const gint8 med_dash_dot_pattern[] = { 9, 3, 3, 3 };
static const double med_dash_dot_pattern_d[] = { 9., 3., 3., 3. };
static const struct LineDotPattern med_dash_dot_line =
{ sizeof (med_dash_dot_pattern), med_dash_dot_pattern, med_dash_dot_pattern_d };
static const gint8 dash_dot_dot_pattern[] = { 3, 3, 9, 3, 3, 3 };
static const double dash_dot_dot_pattern_d[] = { 3., 3., 9., 3., 3., 3. };
static const struct LineDotPattern dash_dot_dot_line =
{ sizeof (dash_dot_dot_pattern), dash_dot_dot_pattern, dash_dot_dot_pattern_d };
static const gint8 med_dash_dot_dot_pattern[] = { 3, 3, 3, 3, 9, 3 };
static const double med_dash_dot_dot_pattern_d[] = { 3., 3., 3., 3., 9., 3. };
static const struct LineDotPattern med_dash_dot_dot_line =
{ sizeof (med_dash_dot_dot_pattern), med_dash_dot_dot_pattern, med_dash_dot_dot_pattern_d };
static const gint8 slant_pattern[] = { 11, 1, 5, 1 };
static const double slant_pattern_d[] = { 11., 1., 5., 1. };
static const struct LineDotPattern slant_line =
{ sizeof (slant_pattern), slant_pattern, slant_pattern_d };
struct {
gint width;
gint offset;
struct LineDotPattern const * pattern;
} static const style_border_data[] = {
/* 0x0 : STYLE_BORDER_NONE */ { 0, 0, NULL },
/* 0x1 : STYLE_BORDER_THIN */ { 0, 0, NULL },
/* 0x2 : STYLE_BORDER_MEDIUM */ { 2, 0, NULL },
/* 0x3 : STYLE_BORDER_DASHED */ { 1, 0, &dashed_line },
/* 0x4 : STYLE_BORDER_DOTTED */ { 1, 0, &dotted_line },
/* 0x5 : STYLE_BORDER_THICK */ { 3, 0, NULL },
/* 0x6 : STYLE_BORDER_DOUBLE */ { 0, 0, NULL },
/* 0x7 : STYLE_BORDER_HAIR */ { 1, 0, &hair_line },
/* 0x8 : STYLE_BORDER_MEDIUM_DASH */ { 2, 9, &med_dashed_line },
/* 0x9 : STYLE_BORDER_DASH_DOT */ { 1, 0, &dash_dot_line },
/* 0xa : STYLE_BORDER_MEDIUM_DASH_DOT */ { 2, 17,&med_dash_dot_line },
/* 0xb : STYLE_BORDER_DASH_DOT_DOT */ { 1, 0, &dash_dot_dot_line },
/* 0xc : STYLE_BORDER_MEDIUM_DASH_DOT_DOT */ { 2, 21,&med_dash_dot_dot_line },
/* 0xd : STYLE_BORDER_SLANTED_DASH_DOT */ { 2, 6, &slant_line },/* How to slant */
/* 0xe : STYLE_BORDER_INCONSISTENT */ { 3, 0, &hair_line },
};
static GHashTable *border_hash = NULL;
static gint
style_border_equal (gconstpointer v1, gconstpointer v2)
{
GnmBorder const *k1 = (GnmBorder const *) v1;
GnmBorder const *k2 = (GnmBorder const *) v2;
/*
* ->color is a pointer, but the comparison is safe because
* all colours are cached, see style_color_new.
*/
return (k1->color == k2->color) &&
(k1->line_type == k2->line_type);
}
static guint
style_border_hash (gconstpointer v)
{
GnmBorder const *b = (GnmBorder const *) v;
/*
* HACK ALERT!
*
* ->color is a pointer, but the comparison is safe because
* all colours are cached, see style_color_new.
*
* We assume that casting a pointer to (unsigned) does something
* useful. That's probably ok.
*/
return (((unsigned)b->color) ^ b->line_type);
}
GnmBorder *
style_border_none (void)
{
static GnmBorder * none = NULL;
if (none == NULL) {
none = g_new0 (GnmBorder, 1);
none->line_type = STYLE_BORDER_NONE;
none->color = style_color_grid ();
none->begin_margin = none->end_margin = none->width = 0;
none->ref_count = 1;
}
g_return_val_if_fail (none != NULL, NULL);
return none;
}
/**
* style_border_none_set_color:
* @color :
*
* This function updates the color of style_border_none when the wanted grid
* color is known. style_border_none tells how to render the grid. Because
* the grid color may be different for different sheets, the functions which
* render the grid call this function first. The rule for selecting the
* grid color, which is the same as in Excel, is: - if the auto pattern
* color is default (which is black), the grid color is gray, as returned by
* style_color_grid (). - otherwise, the auto pattern color is used for the
* grid.
* NOTE : Absorbs a reference to @color.
*/
void
style_border_none_set_color (GnmColor *color)
{
GnmBorder *none = style_border_none ();
GnmColor *nc;
if (color == none->color) {
style_color_unref (color);
return;
}
nc = none->color;
none->color = color;
style_color_unref (nc);
if (none->gc) {
gdk_gc_set_rgb_fg_color (none->gc, &none->color->color);
}
}
/**
* style_border_fetch :
*
* @line_type : dash style
* @color : colour
* @orientation : Not currently used.
*
* Fetches a GnmBorder from the cache, creating one if necessary. Absorbs
* the colour reference. In the future we may have different dash styles for
* the same pattern depending on whether this is a horizontal or vertical line.
*/
GnmBorder *
style_border_fetch (StyleBorderType const line_type,
GnmColor *color,
StyleBorderOrientation orientation)
{
GnmBorder *border;
GnmBorder key;
g_return_val_if_fail (line_type >= STYLE_BORDER_NONE, NULL);
g_return_val_if_fail (line_type < STYLE_BORDER_MAX, NULL);
if (line_type == STYLE_BORDER_NONE) {
if (color)
style_color_unref (color);
return style_border_ref (style_border_none ());
}
g_return_val_if_fail (color != NULL, NULL);
key.line_type = line_type;
key.color = color;
if (border_hash) {
border = g_hash_table_lookup (border_hash, &key);
if (border != NULL) {
if (color)
style_color_unref (color);
return style_border_ref (border);
}
} else
border_hash = g_hash_table_new (style_border_hash,
style_border_equal);
border = g_new0 (GnmBorder, 1);
*border = key;
g_hash_table_insert (border_hash, border, border);
border->ref_count = 1;
border->gc = NULL;
border->gc_screen = NULL;
border->width = style_border_get_width (line_type);
if (border->line_type == STYLE_BORDER_DOUBLE) {
border->begin_margin = 1;
border->end_margin = 1;
} else {
border->begin_margin = (border->width) > 1 ? 1 : 0;
border->end_margin = (border->width) > 2 ? 1 : 0;
}
return border;
}
gboolean
style_border_visible_in_blank (GnmBorder const *border)
{
g_return_val_if_fail (border != NULL, FALSE);
return border->line_type != STYLE_BORDER_NONE;
}
gint
style_border_get_width (StyleBorderType const line_type)
{
g_return_val_if_fail (line_type >= STYLE_BORDER_NONE, 0);
g_return_val_if_fail (line_type < STYLE_BORDER_MAX, 0);
if (line_type == STYLE_BORDER_NONE)
return 0;
return style_border_data [line_type].width;
}
StyleBorderOrientation
style_border_get_orientation (StyleBorderLocation type)
{
switch (type) {
case STYLE_BORDER_LEFT:
case STYLE_BORDER_RIGHT:
return STYLE_BORDER_VERTICAL;
case STYLE_BORDER_DIAG:
case STYLE_BORDER_REV_DIAG:
return STYLE_BORDER_DIAGONAL;
case STYLE_BORDER_TOP:
case STYLE_BORDER_BOTTOM:
default:
return STYLE_BORDER_HORIZONTAL;
}
}
void
style_border_set_gc_dash (GdkGC *gc, StyleBorderType const i)
{
GdkLineStyle style = GDK_LINE_SOLID;
g_return_if_fail (gc != NULL);
g_return_if_fail (i >= STYLE_BORDER_NONE);
g_return_if_fail (i < STYLE_BORDER_MAX);
if (style_border_data[i].pattern != NULL)
style = GDK_LINE_ON_OFF_DASH;
/* NOTE : Tricky. We Use CAP_NOT_LAST because with butt lines
* of width > 0 seem to exclude the far point (under Xfree86-4).
* The Docs for X11R6 say that NotLast will give the same behavior for
* lines of width 0. Strangely the R5 docs say this for 0 AND 1.
*/
gdk_gc_set_line_attributes (gc, style_border_data[i].width, style,
GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
if (style_border_data[i].pattern != NULL) {
struct LineDotPattern const * const pat =
style_border_data[i].pattern;
gdk_gc_set_dashes (gc, style_border_data[i].offset,
(gint8 *)pat->pattern, pat->elements);
}
/* The background should never be drawn */
gdk_gc_set_rgb_bg_color (gc, &gs_white);
}
static inline GdkGC *
style_border_get_gc (GnmBorder const *border, GdkDrawable *drawable)
{
GdkScreen *this_screen;
if (border == NULL)
return NULL;
this_screen = gdk_drawable_get_screen (drawable);
if (border->gc_screen != this_screen) {
if (border->gc)
g_object_unref (G_OBJECT (border->gc));
if (border->gc_screen)
g_object_unref (G_OBJECT (border->gc_screen));
((GnmBorder *)border)->gc = gdk_gc_new (drawable);
((GnmBorder *)border)->gc_screen = this_screen;
g_object_ref (this_screen);
style_border_set_gc_dash (border->gc, border->line_type);
gdk_gc_set_rgb_fg_color (border->gc, &border->color->color);
}
return border->gc;
}
static void
style_border_set_pc_dash (StyleBorderType const i,
GnomePrintContext *context)
{
GdkLineStyle style = GDK_LINE_SOLID;
int w;
g_return_if_fail (context != NULL);
g_return_if_fail (i >= STYLE_BORDER_NONE);
g_return_if_fail (i < STYLE_BORDER_MAX);
if (i == STYLE_BORDER_NONE)
return;
if (style_border_data[i].pattern != NULL)
style = GDK_LINE_ON_OFF_DASH;
w = style_border_data[i].width;
if (w == 0)
w = 1;
gnome_print_setlinewidth (context, w);
if (style_border_data[i].pattern != NULL) {
struct LineDotPattern const * const pat =
style_border_data[i].pattern;
gnome_print_setdash (context, pat->elements,
pat->pattern_d, style_border_data[i].offset);
}
}
static inline gboolean
style_border_set_pc (GnmBorder const * const border,
GnomePrintContext *context)
{
if (border == NULL)
return FALSE;
gnome_print_gsave (context);
style_border_set_pc_dash (border->line_type, context);
gnome_print_setrgbcolor (context,
border->color->color.red / (double) 0xffff,
border->color->color.green / (double) 0xffff,
border->color->color.blue / (double) 0xffff);
return TRUE;
}
GnmBorder *
style_border_ref (GnmBorder *border)
{
/* NULL is ok */
if (border != NULL)
++border->ref_count;
return border;
}
void
style_border_unref (GnmBorder *border)
{
if (border == NULL)
return;
g_return_if_fail (border->ref_count > 0);
border->ref_count--;
if (border->ref_count != 0)
return;
/* Just to be on the safe side.
* We are allowed to deref the border_none,
* but not to free it.
*/
g_return_if_fail (border != style_border_none ());
/* Remove here, before we mess with the hashed fields. */
g_hash_table_remove (border_hash, border);
if (border->color) {
style_color_unref (border->color);
border->color = NULL;
}
if (border->gc) {
g_object_unref (G_OBJECT (border->gc));
border->gc = NULL;
}
if (border->gc_screen) {
g_object_unref (G_OBJECT (border->gc_screen));
border->gc_screen = NULL;
}
g_free (border);
}
#if 0
static gboolean
style_border_hmargins (GnmBorder const * const * prev_vert,
GnmRow const *sr, int col,
int offsets [2][2])
{
GnmBorder const *border = sr->top [col];
GnmBorder const *t0 = prev_vert [col];
GnmBorder const *t1 = prev_vert [col+1];
GnmBorder const *b0 = sr->vertical [col];
GnmBorder const *b1 = sr->vertical [col+1];
if (border->line_type == STYLE_BORDER_DOUBLE) {
/* pull inwards or outwards */
if (!style_border_is_blank (t0)) {
if (t0->line_type == STYLE_BORDER_DOUBLE)
offsets [1][0] = t0->end_margin;
else
offsets [1][0] = -t0->begin_margin;
} else if (!style_border_is_blank (b0))
offsets [1][0] = -b0->begin_margin;
else
offsets [1][0] = 0;
if (!style_border_is_blank (t1)) {
if (t1->line_type == STYLE_BORDER_DOUBLE)
offsets [1][1] = -t1->begin_margin;
else
offsets [1][1] = t1->end_margin;
} else if (!style_border_is_blank (b1))
offsets [1][1] = b1->end_margin;
else
offsets [1][1] = 0;
if (!style_border_is_blank (b0)) {
if (b0->line_type == STYLE_BORDER_DOUBLE)
offsets [0][0] = b0->end_margin;
else
offsets [0][0]= -b0->begin_margin;
} else if (!style_border_is_blank (t0))
offsets [0][0]= -t0->begin_margin;
else
offsets [0][0]= 0;
if (!style_border_is_blank (b1)) {
if (b1->line_type == STYLE_BORDER_DOUBLE)
offsets [0][1] = -b1->begin_margin;
else
offsets [0][1] = b1->end_margin;
} else if (!style_border_is_blank (t1))
offsets [0][1] = t1->end_margin;
else
offsets [0][1] = 0;
return TRUE;
}
offsets [0][0] = offsets [0][1] = 0;
if (border->line_type == STYLE_BORDER_NONE) {
/* No need to check for show grid. That is done when the
* borders are loaded. Do not over write background patterns
*/
if (!style_border_is_blank (b0))
offsets [0][0] = 1 + b0->end_margin;
else if (!style_border_is_blank (t0))
offsets [0][0] = 1 + t0->end_margin;
else if (sr->top [col-1] == NULL)
offsets [0][0] = 1;
if (!style_border_is_blank (b1))
offsets [0][1] = -1 - b1->begin_margin;
else if (!style_border_is_blank (t1))
offsets [0][1] = -1 - t1->begin_margin;
else if (sr->top [col+1] == NULL)
offsets [0][1] = -1;
} else {
/* pull outwards */
if (style_border_is_blank (sr->top [col-1])) {
int offset = 0;
if (!style_border_is_blank (b0))
offset = b0->begin_margin;
if (!style_border_is_blank (t0)) {
int tmp = t0->begin_margin;
if (offset < tmp)
offset = tmp;
}
offsets [0][0] = -offset;
}
if (style_border_is_blank (sr->top [col+1])) {
int offset = 0;
if (!style_border_is_blank (b1))
offset = b1->end_margin;
if (!style_border_is_blank (t1)) {
int tmp = t1->end_margin;
if (offset < tmp)
offset = tmp;
}
offsets [0][1] = offset;
}
}
return FALSE;
}
static gboolean
style_border_vmargins (GnmBorder const * const * prev_vert,
GnmRow const *sr, int col,
int offsets [2][2])
{
GnmBorder const *border = sr->vertical [col];
GnmBorder const *l0 = sr->top [col-1];
GnmBorder const *r0 = sr->top [col];
GnmBorder const *l1 = sr->bottom [col-1];
GnmBorder const *r1 = sr->bottom [col];
if (border->line_type == STYLE_BORDER_DOUBLE) {
/* pull inwards or outwards */
if (!style_border_is_blank (l0))
offsets [1][0] = l0->end_margin;
else if (!style_border_is_blank (r0))
offsets [1][0] = -r0->begin_margin;
else
offsets [1][0] = 0;
if (!style_border_is_blank (l1))
offsets [1][1] = -l1->begin_margin;
else if (!style_border_is_blank (r1))
offsets [1][1] = r1->end_margin;
else
offsets [1][1] = 0;
if (!style_border_is_blank (r0))
offsets [0][0] = r0->end_margin;
else if (!style_border_is_blank (l0))
offsets [0][0] = -l0->begin_margin;
else
offsets [0][0] = 0;
if (!style_border_is_blank (r1))
offsets [0][1] = -r1->begin_margin;
else if (!style_border_is_blank (l1))
offsets [0][1] = l1->end_margin;
else
offsets [0][1] = 0;
return TRUE;
}
offsets [0][0] = offsets [0][1] = 0;
if (border->line_type == STYLE_BORDER_NONE) {
/* No need to check for show grid. That is done when the
* borders are loaded.
*/
if (!style_border_is_blank (r0))
offsets [0][0] = 1 + r0->end_margin;
else if (!style_border_is_blank (l0))
offsets [0][0] = 1 + l0->end_margin;
/* Do not over write background patterns */
else if (prev_vert [col] == NULL)
offsets [0][0] = 1;
if (!style_border_is_blank (r1))
offsets [0][1] = -1 - r1->begin_margin;
else if (!style_border_is_blank (l1))
offsets [0][1] = -1 - l1->begin_margin;
/* Do not over write background patterns */
else if (sr->vertical [col] == NULL)
offsets [0][1] = -1;
} else {
/* pull inwards */
int offset = 0;
if (!style_border_is_blank (r0))
offset = 1 + r0->end_margin;
if (!style_border_is_blank (l0)) {
int tmp = 1 + l0->end_margin;
if (offset < tmp)
offset = tmp;
}
offsets [0][0] = offset;
offset = 0;
if (!style_border_is_blank (r1))
offset = 1 + r1->begin_margin;
if (!style_border_is_blank (l1)) {
int tmp = 1 + l1->begin_margin;
if (offset < tmp)
offset = tmp;
}
offsets [0][1] = -offset;
}
return FALSE;
}
/**
* style_borders_row_draw :
*
* TODO : This is not the final resting place for this.
* It will move into the gui layer eventually.
*/
void
style_borders_row_draw (GnmBorder const * const * prev_vert,
GnmRow const *sr,
GdkDrawable * const drawable,
int x, int y1, int y2,
int *colwidths, gboolean draw_vertical)
{
int o[2][2];
int col, next_x = x;
GdkGC *gc;
for (col = sr->start_col; col <= sr->end_col ; col++, x = next_x) {
if (colwidths[col] == -1)
continue;
next_x = x + colwidths[col];
gc = style_border_get_gc (sr->top [col], drawable);
if (gc != NULL) {
int y = y1;
if (style_border_hmargins (prev_vert, sr, col, o)) {
gdk_draw_line (drawable, gc, x + o[1][0], y1-1,
next_x + o[1][1] + 1, y1-1);
++y;
}
/* See note in style_border_set_gc_dash about +1 */
gdk_draw_line (drawable, gc, x + o[0][0], y,
next_x + o[0][1] + 1, y);
}
if (!draw_vertical)
continue;
gc = style_border_get_gc (sr->vertical [col], drawable);
if (gc != NULL) {
int x1 = x;
if (style_border_vmargins (prev_vert, sr, col, o)) {
gdk_draw_line (drawable, gc, x-1, y1 + o[1][0],
x-1, y2 + o[1][1] + 1);
++x1;
}
/* See note in style_border_set_gc_dash about +1 */
gdk_draw_line (drawable, gc, x1, y1 + o[0][0],
x1, y2 + o[0][1] + 1);
}
}
if (draw_vertical) {
gc = style_border_get_gc (sr->vertical [col], drawable);
if (gc != NULL) {
int x1 = x;
if (style_border_vmargins (prev_vert, sr, col, o)) {
gdk_draw_line (drawable, gc, x-1, y1 + o[1][0],
x-1, y2 + o[1][1] + 1);
++x1;
}
/* See note in style_border_set_gc_dash about +1 */
gdk_draw_line (drawable, gc, x, y1 + o[0][0],
x1, y2 + o[0][1] + 1);
}
}
}
#endif /* GnmRow... */
void
style_border_draw_diag (GnmStyle const *style,
GdkDrawable *drawable,
int x1, int y1, int x2, int y2)
{
GnmBorder const *diag;
GdkGC *gc;
diag = mstyle_get_border (style, MSTYLE_BORDER_REV_DIAGONAL);
if (diag != NULL && diag->line_type != STYLE_BORDER_NONE) {
gc = style_border_get_gc (diag, drawable);
if (diag->line_type == STYLE_BORDER_DOUBLE) {
gdk_draw_line (drawable, gc, x1+1, y1+3, x2-3, y2-1);
gdk_draw_line (drawable, gc, x1+3, y1+1, x2-1, y2-3);
} else
gdk_draw_line (drawable, gc, x1, y1, x2, y2);
}
diag = mstyle_get_border (style, MSTYLE_BORDER_DIAGONAL);
if (diag != NULL && diag->line_type != STYLE_BORDER_NONE) {
gc = style_border_get_gc (diag, drawable);
if (diag->line_type == STYLE_BORDER_DOUBLE) {
gdk_draw_line (drawable, gc, x1+1, y2-3, x2-3, y1+1);
gdk_draw_line (drawable, gc, x1+3, y2-1, x2-1, y1+3);
} else
gdk_draw_line (drawable, gc, x1, y2, x2, y1);
}
}
static inline void
print_hline (GnomePrintContext *context,
float x1, float x2, float y, int width)
{
if (width == 0 || width % 2)
y -= .5;
/* exclude far pixel to match gdk */
gnome_print_moveto (context, x1, y);
gnome_print_lineto (context, x2, y);
gnome_print_stroke (context);
}
static inline void
print_vline (GnomePrintContext *context,
float x, float y1, float y2, int width)
{
if (width == 0 || width % 2)
x += .5;
/* exclude far pixel to match gdk */
gnome_print_moveto (context, x, y1);
gnome_print_lineto (context, x, y2);
gnome_print_stroke (context);
}
#if 0 // Sheet, Row
void
style_borders_row_print (GnmBorder const * const * prev_vert,
GnmRow const *sr,
GnomePrintContext *context,
float x, float y1, float y2,
Sheet const *sheet, gboolean draw_vertical)
{
int o[2][2], col;
float next_x = x;
GnmBorder const *border;
for (col = sr->start_col; col <= sr->end_col ; col++, x = next_x) {
/* TODO : make this sheet agnostic. Pass in an array of
* widths and a flag for whether or not to draw grids.
*/
ColRowInfo const *cri = sheet_col_get_info (sheet, col);
if (!cri->visible)
continue;
next_x = x + cri->size_pts;
border = sr->top [col];
if (style_border_set_pc (border, context)) {
float y = y1;
if (style_border_hmargins (prev_vert, sr, col, o)) {
print_hline (context, x + o[1][0],
next_x + o[1][1] + 1., y1+1., border->width);
--y;
}
print_hline (context, x + o[0][0],
next_x + o[0][1] + 1., y, border->width);
gnome_print_grestore (context);
}
if (!draw_vertical)
continue;
border = sr->vertical [col];
if (style_border_set_pc (border, context)) {
float x1 = x;
if (style_border_vmargins (prev_vert, sr, col, o)) {
print_vline (context, x-1., y1 - o[1][0],
y2 - o[1][1] - 1., border->width);
++x1;
}
print_vline (context, x1, y1 - o[0][0],
y2 - o[0][1] - 1., border->width);
gnome_print_grestore (context);
}
}
if (draw_vertical) {
border = sr->vertical [col];
if (style_border_set_pc (border, context)) {
float x1 = x;
if (style_border_vmargins (prev_vert, sr, col, o)) {
print_vline (context, x-1., y1 - o[1][0] - 1.,
y2 - o[1][1], border->width);
++x1;
}
/* See note in style_border_set_gc_dash about +1 */
print_vline (context, x, y1 - o[0][0],
y2 - o[0][1] - 1, border->width);
gnome_print_grestore (context);
}
}
}
#endif // 0
void
style_border_print_diag (GnmStyle const *style,
GnomePrintContext *context,
float x1, float y1, float x2, float y2)
{
GnmBorder const *diag;
diag = mstyle_get_border (style, MSTYLE_BORDER_REV_DIAGONAL);
if (diag != NULL && diag->line_type != STYLE_BORDER_NONE) {
style_border_set_pc (diag, context);
if (diag->line_type == STYLE_BORDER_DOUBLE) {
gnome_print_moveto (context, x1+1.5, y1-3.);
gnome_print_lineto (context, x2-2., y2+ .5);
gnome_print_stroke (context);
gnome_print_moveto (context, x1+ 3., y1-1.5);
gnome_print_lineto (context, x2- .5, y2+2.);
} else {
gnome_print_moveto (context, x1+.5, y1-.5);
gnome_print_lineto (context, x2+.5, y2-.5);
}
gnome_print_stroke (context);
gnome_print_grestore (context);
}
diag = mstyle_get_border (style, MSTYLE_BORDER_DIAGONAL);
if (diag != NULL && diag->line_type != STYLE_BORDER_NONE) {
style_border_set_pc (diag, context);
if (diag->line_type == STYLE_BORDER_DOUBLE) {
gnome_print_moveto (context, x1+1.5, y2+2.);
gnome_print_lineto (context, x2-2., y1-1.5);
gnome_print_stroke (context);
gnome_print_moveto (context, x1+3., y2+ .5);
gnome_print_lineto (context, x2- .5, y1-3.);
} else {
gnome_print_moveto (context, x1+.5, y2-.5);
gnome_print_lineto (context, x2+.5, y1-.5);
}
gnome_print_stroke (context);
gnome_print_grestore (context);
}
}