3 * border.c: Managing drawing and printing cell borders
5 * Copyright (C) 1999-2001 Jody Goldberg (jody@gnome.org)
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
22 #include <gnumeric-config.h>
24 #include <style-border.h>
26 #include <style-color.h>
28 #include <sheet-style.h>
33 struct LineDotPattern
{
35 const gint8
*const pattern
;
36 const double *const pattern_d
;
39 static const gint8 dashed_pattern
[] = { 3, 1 };
40 static const double dashed_pattern_d
[] = { 3., 1. };
41 static const struct LineDotPattern dashed_line
=
42 { sizeof (dashed_pattern
), dashed_pattern
, dashed_pattern_d
};
44 static const gint8 med_dashed_pattern
[] = { 9, 3 };
45 static const double med_dashed_pattern_d
[] = { 9., 3. };
46 static const struct LineDotPattern med_dashed_line
=
47 { sizeof (med_dashed_pattern
), med_dashed_pattern
, med_dashed_pattern_d
};
49 static const gint8 dotted_pattern
[] = { 2, 2 };
50 static const double dotted_pattern_d
[] = { 2., 2. };
51 static const struct LineDotPattern dotted_line
=
52 { sizeof (dotted_pattern
), dotted_pattern
, dotted_pattern_d
};
54 static const gint8 hair_pattern
[] = { 1, 1 };
55 static const double hair_pattern_d
[] = { 1., 1. };
56 static const struct LineDotPattern hair_line
=
57 { sizeof (hair_pattern
), hair_pattern
, hair_pattern_d
};
59 static const gint8 dash_dot_pattern
[] = { 8, 3, 3, 3 };
60 static const double dash_dot_pattern_d
[] = { 8., 3., 3., 3. };
61 static const struct LineDotPattern dash_dot_line
=
62 { sizeof (dash_dot_pattern
), dash_dot_pattern
, dash_dot_pattern_d
};
64 static const gint8 med_dash_dot_pattern
[] = { 9, 3, 3, 3 };
65 static const double med_dash_dot_pattern_d
[] = { 9., 3., 3., 3. };
66 static const struct LineDotPattern med_dash_dot_line
=
67 { sizeof (med_dash_dot_pattern
), med_dash_dot_pattern
, med_dash_dot_pattern_d
};
69 static const gint8 dash_dot_dot_pattern
[] = { 3, 3, 9, 3, 3, 3 };
70 static const double dash_dot_dot_pattern_d
[] = { 3., 3., 9., 3., 3., 3. };
71 static const struct LineDotPattern dash_dot_dot_line
=
72 { sizeof (dash_dot_dot_pattern
), dash_dot_dot_pattern
, dash_dot_dot_pattern_d
};
74 static const gint8 med_dash_dot_dot_pattern
[] = { 3, 3, 3, 3, 9, 3 };
75 static const double med_dash_dot_dot_pattern_d
[] = { 3., 3., 3., 3., 9., 3. };
76 static const struct LineDotPattern med_dash_dot_dot_line
=
77 { sizeof (med_dash_dot_dot_pattern
), med_dash_dot_dot_pattern
, med_dash_dot_dot_pattern_d
};
79 static const gint8 slant_pattern
[] = { 11, 1, 5, 1 };
80 static const double slant_pattern_d
[] = { 11., 1., 5., 1. };
81 static const struct LineDotPattern slant_line
=
82 { sizeof (slant_pattern
), slant_pattern
, slant_pattern_d
};
87 struct LineDotPattern
const * pattern
;
88 } static const style_border_data
[] = {
89 /* 0x0 : GNM_STYLE_BORDER_NONE */ { 0, 0, NULL
},
90 /* 0x1 : GNM_STYLE_BORDER_THIN */ { 0, 0, NULL
},
91 /* 0x2 : GNM_STYLE_BORDER_MEDIUM */ { 2, 0, NULL
},
92 /* 0x3 : GNM_STYLE_BORDER_DASHED */ { 1, 0, &dashed_line
},
93 /* 0x4 : GNM_STYLE_BORDER_DOTTED */ { 1, 0, &dotted_line
},
94 /* 0x5 : GNM_STYLE_BORDER_THICK */ { 3, 0, NULL
},
95 /* 0x6 : GNM_STYLE_BORDER_DOUBLE */ { 0, 0, NULL
},
96 /* 0x7 : GNM_STYLE_BORDER_HAIR */ { 1, 0, &hair_line
},
97 /* 0x8 : GNM_STYLE_BORDER_MEDIUM_DASH */ { 2, 9, &med_dashed_line
},
98 /* 0x9 : GNM_STYLE_BORDER_DASH_DOT */ { 1, 0, &dash_dot_line
},
99 /* 0xa : GNM_STYLE_BORDER_MEDIUM_DASH_DOT */ { 2, 17,&med_dash_dot_line
},
100 /* 0xb : GNM_STYLE_BORDER_DASH_DOT_DOT */ { 1, 0, &dash_dot_dot_line
},
101 /* 0xc : GNM_STYLE_BORDER_MEDIUM_DASH_DOT_DOT */ { 2, 21,&med_dash_dot_dot_line
},
102 /* 0xd : GNM_STYLE_BORDER_SLANTED_DASH_DOT */ { 2, 6, &slant_line
},/* How to slant */
103 /* 0xe : GNM_STYLE_BORDER_INCONSISTENT */ { 3, 0, &hair_line
},
106 static GHashTable
*border_hash
= NULL
;
107 static GnmBorder
*border_none
= NULL
;
110 style_border_equal (gconstpointer v1
, gconstpointer v2
)
112 GnmBorder
const *k1
= (GnmBorder
const *) v1
;
113 GnmBorder
const *k2
= (GnmBorder
const *) v2
;
116 * ->color is a pointer, but the comparison is safe because
117 * all colours are cached, see gnm_color_new_go.
119 return (k1
->color
== k2
->color
) &&
120 (k1
->line_type
== k2
->line_type
);
124 style_border_hash (gconstpointer v
)
126 GnmBorder
const *b
= (GnmBorder
const *) v
;
131 * ->color is a pointer, but the comparison is safe because
132 * all colours are cached, see gnm_color_new_go.
135 return (GPOINTER_TO_UINT(b
->color
) ^ b
->line_type
);
139 * gnm_style_border_none:
141 * Returns: (transfer none): A #GnmBorder with no borders.
144 gnm_style_border_none (void)
146 if (border_none
== NULL
) {
147 border_none
= g_new0 (GnmBorder
, 1);
148 border_none
->line_type
= GNM_STYLE_BORDER_NONE
;
149 border_none
->color
= style_color_grid ();
150 border_none
->begin_margin
= border_none
->end_margin
= border_none
->width
= 0;
151 border_none
->ref_count
= 1;
152 /* Note: not in the hash. */
155 g_return_val_if_fail (border_none
!= NULL
, NULL
);
161 * gnm_style_border_none_set_color:
162 * @color: (transfer full): #GnmColor
164 * This function updates the color of gnm_style_border_none when the wanted grid
165 * color is known. gnm_style_border_none tells how to render the grid. Because
166 * the grid color may be different for different sheets, the functions which
167 * render the grid call this function first. The rule for selecting the
168 * grid color, which is the same as in Excel, is: - if the auto pattern
169 * color is default (which is black), the grid color is gray, as returned by
170 * style_color_grid (). - otherwise, the auto pattern color is used for the
174 gnm_style_border_none_set_color (GnmColor
*color
)
176 GnmBorder
*none
= gnm_style_border_none ();
179 if (color
== none
->color
) {
180 style_color_unref (color
);
186 style_color_unref (nc
);
190 * gnm_style_border_fetch:
191 * @line_type: dash style
192 * @color: (transfer full) (nullable): colour
193 * @orientation: Not currently used.
195 * Returns: (transfer full): A #GnmBorder
198 gnm_style_border_fetch (GnmStyleBorderType line_type
,
200 GnmStyleBorderOrientation orientation
)
205 if (line_type
< GNM_STYLE_BORDER_NONE
|| line_type
> GNM_STYLE_BORDER_MAX
) {
206 g_warning ("Invalid border type: %d", line_type
);
207 line_type
= GNM_STYLE_BORDER_NONE
;
210 if (line_type
== GNM_STYLE_BORDER_NONE
) {
211 style_color_unref (color
);
212 return gnm_style_border_ref (gnm_style_border_none ());
215 g_return_val_if_fail (color
!= NULL
, NULL
);
216 memset (&key
, 0, sizeof (key
));
217 key
.line_type
= line_type
;
221 border
= g_hash_table_lookup (border_hash
, &key
);
222 if (border
!= NULL
) {
223 style_color_unref (color
);
224 return gnm_style_border_ref (border
);
227 border_hash
= g_hash_table_new (style_border_hash
,
230 border
= g_memdup (&key
, sizeof (key
));
231 border
->ref_count
= 1;
232 border
->width
= gnm_style_border_get_width (line_type
);
233 if (border
->line_type
== GNM_STYLE_BORDER_DOUBLE
) {
234 border
->begin_margin
= 1;
235 border
->end_margin
= 1;
237 border
->begin_margin
= (border
->width
) > 1 ? 1 : 0;
238 border
->end_margin
= (border
->width
) > 2 ? 1 : 0;
240 g_hash_table_insert (border_hash
, border
, border
);
246 gnm_style_border_visible_in_blank (GnmBorder
const *border
)
248 g_return_val_if_fail (border
!= NULL
, FALSE
);
250 return border
->line_type
!= GNM_STYLE_BORDER_NONE
;
254 gnm_style_border_get_width (GnmStyleBorderType
const line_type
)
256 g_return_val_if_fail (line_type
>= GNM_STYLE_BORDER_NONE
, 0);
257 g_return_val_if_fail (line_type
< GNM_STYLE_BORDER_MAX
, 0);
259 if (line_type
== GNM_STYLE_BORDER_NONE
)
262 return style_border_data
[line_type
].width
;
265 GnmStyleBorderOrientation
266 gnm_style_border_get_orientation (GnmStyleBorderLocation type
)
269 case GNM_STYLE_BORDER_LEFT
:
270 case GNM_STYLE_BORDER_RIGHT
:
271 return GNM_STYLE_BORDER_VERTICAL
;
272 case GNM_STYLE_BORDER_DIAG
:
273 case GNM_STYLE_BORDER_REV_DIAG
:
274 return GNM_STYLE_BORDER_DIAGONAL
;
275 case GNM_STYLE_BORDER_TOP
:
276 case GNM_STYLE_BORDER_BOTTOM
:
278 return GNM_STYLE_BORDER_HORIZONTAL
;
283 * gnm_style_border_ref:
284 * @border: (nullable): #GnmBorder
286 * Returns: (transfer full): a reference to @border
289 gnm_style_border_ref (GnmBorder
*border
)
292 if (border
!= NULL
) {
294 if (0) g_printerr ("style border ref: %p [color=%p]\n", border
, border
->color
);
300 * gnm_style_border_unref:
301 * @border: (transfer full) (nullable): #GnmBorder
304 gnm_style_border_unref (GnmBorder
*border
)
309 g_return_if_fail (border
->ref_count
> 0);
311 if (0) g_printerr ("style border unref: %p\n", border
);
314 if (border
->ref_count
!= 0)
318 * We are allowed to deref border_none, but not to free it.
319 * It is not in the hash.
321 g_return_if_fail (border
!= border_none
);
323 /* Remove here, before we mess with the hashed fields. */
324 g_hash_table_remove (border_hash
, border
);
326 style_color_unref (border
->color
);
327 border
->color
= NULL
;
333 cb_border_leak (gpointer key
, gpointer value
, gpointer user_data
)
335 GnmBorder
*border
= value
;
337 g_printerr ("Leaking style-border at %p [color=%p line=%d] refs=%d.\n",
345 * gnm_border_shutdown: (skip)
348 gnm_border_shutdown (void)
351 if (border_none
->ref_count
== 1) {
352 style_color_unref (border_none
->color
);
353 g_free (border_none
);
355 cb_border_leak (NULL
, border_none
, NULL
);
361 g_hash_table_foreach (border_hash
, cb_border_leak
, NULL
);
362 g_hash_table_destroy (border_hash
);
368 gnm_border_get_type (void)
373 t
= g_boxed_type_register_static ("GnmBorder",
374 (GBoxedCopyFunc
)gnm_style_border_ref
,
375 (GBoxedFreeFunc
)gnm_style_border_unref
);
381 style_border_hmargins (GnmBorder
const * const * prev_vert
,
382 GnmStyleRow
const *sr
, int col
,
383 int offsets
[2][2], int dir
)
385 GnmBorder
const *border
= sr
->top
[col
];
386 GnmBorder
const *t0
= prev_vert
[col
];
387 GnmBorder
const *t1
= prev_vert
[col
+1];
388 GnmBorder
const *b0
= sr
->vertical
[col
];
389 GnmBorder
const *b1
= sr
->vertical
[col
+1];
391 if (border
->line_type
== GNM_STYLE_BORDER_DOUBLE
) {
392 /* pull inwards or outwards */
393 if (!gnm_style_border_is_blank (t0
)) {
394 if (t0
->line_type
== GNM_STYLE_BORDER_DOUBLE
)
395 offsets
[1][0] = dir
* t0
->end_margin
;
397 offsets
[1][0] = -dir
* t0
->begin_margin
;
398 } else if (!gnm_style_border_is_blank (b0
))
399 offsets
[1][0] = -dir
* b0
->begin_margin
;
403 if (!gnm_style_border_is_blank (t1
)) {
404 if (t1
->line_type
== GNM_STYLE_BORDER_DOUBLE
)
405 offsets
[1][1] = -dir
* t1
->begin_margin
;
407 offsets
[1][1] = dir
* t1
->end_margin
;
408 } else if (!gnm_style_border_is_blank (b1
))
409 offsets
[1][1] = dir
* b1
->end_margin
;
413 if (!gnm_style_border_is_blank (b0
)) {
414 if (b0
->line_type
== GNM_STYLE_BORDER_DOUBLE
)
415 offsets
[0][0] = dir
* b0
->end_margin
;
417 offsets
[0][0]= -dir
* b0
->begin_margin
;
418 } else if (!gnm_style_border_is_blank (t0
))
419 offsets
[0][0]= -dir
* t0
->begin_margin
;
423 if (!gnm_style_border_is_blank (b1
)) {
424 if (b1
->line_type
== GNM_STYLE_BORDER_DOUBLE
)
425 offsets
[0][1] = -dir
* b1
->begin_margin
;
427 offsets
[0][1] = dir
* b1
->end_margin
;
428 } else if (!gnm_style_border_is_blank (t1
))
429 offsets
[0][1] = dir
* t1
->end_margin
;
435 offsets
[0][0] = offsets
[0][1] = 0;
436 if (border
->line_type
== GNM_STYLE_BORDER_NONE
) {
437 /* No need to check for show grid. That is done when the
438 * borders are loaded. Do not over write background patterns
440 if (!gnm_style_border_is_blank (b0
))
441 offsets
[0][0] = dir
*(1 + b0
->end_margin
);
442 else if (!gnm_style_border_is_blank (t0
))
443 offsets
[0][0] = dir
*(1 + t0
->end_margin
);
444 else if (sr
->top
[col
-1] == NULL
)
445 offsets
[0][0] = dir
;
447 if (!gnm_style_border_is_blank (b1
))
448 offsets
[0][1] = -dir
* (1 - b1
->begin_margin
);
449 else if (!gnm_style_border_is_blank (t1
))
450 offsets
[0][1] = -dir
* (1 - t1
->begin_margin
);
451 else if (sr
->top
[col
+1] == NULL
)
452 offsets
[0][1] = -dir
;
455 if (gnm_style_border_is_blank (sr
->top
[col
-1])) {
457 if (!gnm_style_border_is_blank (b0
))
458 offset
= b0
->begin_margin
;
459 if (!gnm_style_border_is_blank (t0
)) {
460 int tmp
= t0
->begin_margin
;
464 offsets
[0][0] = -dir
* offset
;
467 if (gnm_style_border_is_blank (sr
->top
[col
+1])) {
469 if (!gnm_style_border_is_blank (b1
))
470 offset
= b1
->end_margin
;
471 if (!gnm_style_border_is_blank (t1
)) {
472 int tmp
= t1
->end_margin
;
476 offsets
[0][1] = dir
* offset
;
483 style_border_vmargins (GnmBorder
const * const * prev_vert
,
484 GnmStyleRow
const *sr
, int col
,
487 GnmBorder
const *border
= sr
->vertical
[col
];
488 GnmBorder
const *l0
= sr
->top
[col
-1];
489 GnmBorder
const *r0
= sr
->top
[col
];
490 GnmBorder
const *l1
= sr
->bottom
[col
-1];
491 GnmBorder
const *r1
= sr
->bottom
[col
];
493 if (border
->line_type
== GNM_STYLE_BORDER_DOUBLE
) {
494 /* pull inwards or outwards */
495 if (!gnm_style_border_is_blank (l0
))
496 offsets
[1][0] = l0
->end_margin
;
497 else if (!gnm_style_border_is_blank (r0
))
498 offsets
[1][0] = -r0
->begin_margin
;
502 if (!gnm_style_border_is_blank (l1
))
503 offsets
[1][1] = -l1
->begin_margin
;
504 else if (!gnm_style_border_is_blank (r1
))
505 offsets
[1][1] = r1
->end_margin
;
509 if (!gnm_style_border_is_blank (r0
))
510 offsets
[0][0] = r0
->end_margin
;
511 else if (!gnm_style_border_is_blank (l0
))
512 offsets
[0][0] = -l0
->begin_margin
;
516 if (!gnm_style_border_is_blank (r1
))
517 offsets
[0][1] = -r1
->begin_margin
;
518 else if (!gnm_style_border_is_blank (l1
))
519 offsets
[0][1] = l1
->end_margin
;
525 offsets
[0][0] = offsets
[0][1] = 0;
526 if (border
->line_type
== GNM_STYLE_BORDER_NONE
) {
527 /* No need to check for show grid. That is done when the
528 * borders are loaded.
530 if (!gnm_style_border_is_blank (r0
))
531 offsets
[0][0] = 1 + r0
->end_margin
;
532 else if (!gnm_style_border_is_blank (l0
))
533 offsets
[0][0] = 1 + l0
->end_margin
;
534 /* Do not over write background patterns */
535 else if (prev_vert
[col
] == NULL
)
538 if (!gnm_style_border_is_blank (r1
))
539 offsets
[0][1] = -1 - r1
->begin_margin
;
540 else if (!gnm_style_border_is_blank (l1
))
541 offsets
[0][1] = -1 - l1
->begin_margin
;
542 /* Do not over write background patterns */
543 else if (sr
->vertical
[col
] == NULL
)
548 if (!gnm_style_border_is_blank (r0
))
549 offset
= 1 + r0
->end_margin
;
550 if (!gnm_style_border_is_blank (l0
)) {
551 int tmp
= 1 + l0
->end_margin
;
555 offsets
[0][0] = offset
;
558 if (!gnm_style_border_is_blank (r1
))
559 offset
= 1 + r1
->begin_margin
;
560 if (!gnm_style_border_is_blank (l1
)) {
561 int tmp
= 1 + l1
->begin_margin
;
565 offsets
[0][1] = -offset
;
571 gnm_style_border_set_dash (GnmStyleBorderType
const i
,
576 g_return_if_fail (context
!= NULL
);
577 g_return_if_fail (i
>= GNM_STYLE_BORDER_NONE
);
578 g_return_if_fail (i
< GNM_STYLE_BORDER_MAX
);
580 w
= style_border_data
[i
].width
;
583 cairo_set_line_width (context
,((double) w
));
585 if (style_border_data
[i
].pattern
!= NULL
) {
586 struct LineDotPattern
const * const pat
=
587 style_border_data
[i
].pattern
;
588 cairo_set_dash (context
, pat
->pattern_d
, pat
->elements
,
589 style_border_data
[i
].offset
);
591 cairo_set_dash (context
, NULL
, 0, 0);
594 static inline gboolean
595 style_border_set_gtk (GnmBorder
const * const border
,
601 gnm_style_border_set_dash (border
->line_type
, context
);
602 cairo_set_source_rgba (context
,
603 GO_COLOR_TO_CAIRO (border
->color
->go_color
));
608 print_hline_gtk (cairo_t
*context
,
609 double x1
, double x2
, double y
, int width
)
611 if (width
== 0 || width
% 2)
614 /* exclude far pixel to match gdk */
615 cairo_move_to (context
, x1
, y
);
616 cairo_line_to (context
, x2
, y
);
617 cairo_stroke (context
);
621 print_vline_gtk (cairo_t
*context
,
622 double x
, double y1
, double y2
, int width
, int dir
)
624 if (width
== 0 || width
% 2)
627 /* exclude far pixel to match gdk */
628 cairo_move_to (context
, x
, y1
);
629 cairo_line_to (context
, x
, y2
);
630 cairo_stroke (context
);
634 * gnm_style_borders_row_draw:
636 * TODO : This is not the final resting place for this.
637 * It will move into the gui layer eventually.
640 gnm_style_borders_row_draw (GnmBorder
const * const * prev_vert
,
641 GnmStyleRow
const *sr
,
643 int x
, int y1
, int y2
,
645 gboolean draw_vertical
, int dir
)
649 GnmBorder
const *border
;
653 for (col
= sr
->start_col
; col
<= sr
->end_col
; col
++, x
= next_x
) {
655 if (colwidths
[col
] == -1)
657 next_x
= x
+ dir
* colwidths
[col
];
659 border
= sr
->top
[col
];
661 if (style_border_set_gtk (border
, cr
)) {
663 if (style_border_hmargins (prev_vert
, sr
, col
, o
, dir
)) {
664 print_hline_gtk (cr
, x
+ o
[1][0],
665 next_x
+ o
[1][1] + dir
, y1
-1.,
670 /* See note in gnm_style_border_set_gc_dash about +1 */
671 print_hline_gtk (cr
, x
+ o
[0][0],
672 next_x
+ o
[0][1] + dir
, y
, border
->width
);
679 border
= sr
->vertical
[col
];
680 if (style_border_set_gtk (border
, cr
)) {
682 if (style_border_vmargins (prev_vert
, sr
, col
, o
)) {
683 print_vline_gtk (cr
, x
-dir
, y1
+ o
[1][0],
684 y2
+ o
[1][1] + 1., border
->width
, dir
);
687 /* See note in gnm_style_border_set_gc_dash about +1 */
688 print_vline_gtk (cr
, x1
, y1
+ o
[0][0],
689 y2
+ o
[0][1] + 1., border
->width
, dir
);
693 border
= sr
->vertical
[col
];
694 if (style_border_set_gtk (border
, cr
)) {
696 if (style_border_vmargins (prev_vert
, sr
, col
, o
)) {
697 print_vline_gtk (cr
, x
-dir
, y1
+ o
[1][0] + 1.,
698 y2
+ o
[1][1], border
->width
, dir
);
701 /* See note in gnm_style_border_set_gc_dash about +1 */
702 print_vline_gtk (cr
, x1
, y1
+ o
[0][0],
703 y2
+ o
[0][1] + 1, border
->width
, dir
);
711 gnm_style_border_draw_diag (GnmStyle
const *style
,
713 int x1
, int y1
, int x2
, int y2
)
715 GnmBorder
const *diag
;
719 diag
= gnm_style_get_border (style
, MSTYLE_BORDER_REV_DIAGONAL
);
720 if (diag
!= NULL
&& diag
->line_type
!= GNM_STYLE_BORDER_NONE
) {
721 style_border_set_gtk (diag
, cr
);
722 if (diag
->line_type
== GNM_STYLE_BORDER_DOUBLE
) {
723 cairo_move_to (cr
, x1
+1.5, y1
+3.);
724 cairo_line_to (cr
, x2
-2., y2
- .5);
726 cairo_move_to (cr
, x1
+ 3., y1
+1.5);
727 cairo_line_to (cr
, x2
- .5, y2
-2.);
729 cairo_move_to (cr
, x1
+.5, y1
+.5);
730 cairo_line_to (cr
, x2
+.5, y2
+.5);
735 diag
= gnm_style_get_border (style
, MSTYLE_BORDER_DIAGONAL
);
736 if (diag
!= NULL
&& diag
->line_type
!= GNM_STYLE_BORDER_NONE
) {
737 style_border_set_gtk (diag
, cr
);
738 if (diag
->line_type
== GNM_STYLE_BORDER_DOUBLE
) {
739 cairo_move_to (cr
, x1
+1.5, y2
-2.);
740 cairo_line_to (cr
, x2
-2., y1
+1.5);
742 cairo_move_to (cr
, x1
+3., y2
- .5);
743 cairo_line_to (cr
, x2
- .5, y1
+3.);
745 cairo_move_to (cr
, x1
+.5, y2
+.5);
746 cairo_line_to (cr
, x2
+.5, y1
+.5);
755 gnm_style_borders_row_print_gtk (GnmBorder
const * const * prev_vert
,
756 GnmStyleRow
const *sr
,
758 double x
, double y1
, double y2
,
760 gboolean draw_vertical
, int dir
)
764 GnmBorder
const *border
;
765 double const hscale
= sheet
->display_formulas
? 2 : 1;
767 cairo_save (context
);
769 for (col
= sr
->start_col
; col
<= sr
->end_col
; col
++, x
= next_x
) {
770 /* TODO : make this sheet agnostic. Pass in an array of
771 * widths and a flag for whether or not to draw grids.
773 ColRowInfo
const *cri
= sheet_col_get_info (sheet
, col
);
776 next_x
= x
+ dir
* cri
->size_pts
* hscale
;
778 border
= sr
->top
[col
];
780 if (style_border_set_gtk (border
, context
)) {
782 if (style_border_hmargins (prev_vert
, sr
, col
, o
, dir
)) {
783 print_hline_gtk (context
, x
+ o
[1][0],
784 next_x
+ o
[1][1] + dir
, y1
-1.,
789 print_hline_gtk (context
, x
+ o
[0][0],
790 next_x
+ o
[0][1] + dir
, y
, border
->width
);
797 border
= sr
->vertical
[col
];
798 if (style_border_set_gtk (border
, context
)) {
800 if (style_border_vmargins (prev_vert
, sr
, col
, o
)) {
801 print_vline_gtk (context
, x
-dir
, y1
+ o
[1][0],
802 y2
+ o
[1][1] + 1., border
->width
, dir
);
805 print_vline_gtk (context
, x1
, y1
+ o
[0][0],
806 y2
+ o
[0][1] + 1., border
->width
, dir
);
810 border
= sr
->vertical
[col
];
811 if (style_border_set_gtk (border
, context
)) {
813 if (style_border_vmargins (prev_vert
, sr
, col
, o
)) {
814 print_vline_gtk (context
, x
-dir
, y1
+ o
[1][0] + 1.,
815 y2
+ o
[1][1], border
->width
, dir
);
818 /* See note in gnm_style_border_set_gc_dash about +1 */
819 print_vline_gtk (context
, x1
, y1
+ o
[0][0],
820 y2
+ o
[0][1] + 1, border
->width
, dir
);
824 cairo_restore (context
);
828 gnm_style_border_print_diag_gtk (GnmStyle
const *style
,
830 double x1
, double y1
, double x2
, double y2
)
832 GnmBorder
const *diag
;
835 cairo_save (context
);
837 diag
= gnm_style_get_border (style
, MSTYLE_BORDER_REV_DIAGONAL
);
838 if (diag
!= NULL
&& diag
->line_type
!= GNM_STYLE_BORDER_NONE
) {
839 style_border_set_gtk (diag
, context
);
840 if (diag
->line_type
== GNM_STYLE_BORDER_DOUBLE
) {
841 cairo_move_to (context
, x1
+1.5, y1
+3.);
842 cairo_line_to (context
, x2
-2., y2
- .5);
843 cairo_stroke (context
);
844 cairo_move_to (context
, x1
+ 3., y1
+1.5);
845 cairo_line_to (context
, x2
- .5, y2
-2.);
847 cairo_move_to (context
, x1
+.5, y1
+.5);
848 cairo_line_to (context
, x2
+.5, y2
+.5);
850 cairo_stroke (context
);
853 diag
= gnm_style_get_border (style
, MSTYLE_BORDER_DIAGONAL
);
854 if (diag
!= NULL
&& diag
->line_type
!= GNM_STYLE_BORDER_NONE
) {
855 style_border_set_gtk (diag
, context
);
856 if (diag
->line_type
== GNM_STYLE_BORDER_DOUBLE
) {
857 cairo_move_to (context
, x1
+1.5, y2
-2.);
858 cairo_line_to (context
, x2
-2., y1
+1.5);
859 cairo_stroke (context
);
860 cairo_move_to (context
, x1
+3., y2
- .5);
861 cairo_line_to (context
, x2
- .5, y1
+3.);
863 cairo_move_to (context
, x1
+.5, y2
+.5);
864 cairo_line_to (context
, x2
+.5, y1
+.5);
866 cairo_stroke (context
);
869 cairo_restore (context
);