mirror of https://github.com/Gnucash/gnucash
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.
862 lines
24 KiB
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);
|
|
}
|
|
}
|