Update Spanish translation
[gnumeric.git] / src / style-border.c
blob9200e26ee7a02080163d719e75ff6317e2c32174
2 /*
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
20 * USA
22 #include <gnumeric-config.h>
23 #include <gnumeric.h>
24 #include <style-border.h>
26 #include <style-color.h>
27 #include <style.h>
28 #include <sheet-style.h>
29 #include <sheet.h>
30 #include <gdk/gdk.h>
31 #include <string.h>
33 struct LineDotPattern {
34 const gint elements;
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 };
84 struct {
85 gint width;
86 gint offset;
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;
109 static gint
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);
123 static guint
124 style_border_hash (gconstpointer v)
126 GnmBorder const *b = (GnmBorder const *) v;
129 * HACK ALERT!
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.
143 GnmBorder *
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);
157 return border_none;
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
171 * grid.
173 void
174 gnm_style_border_none_set_color (GnmColor *color)
176 GnmBorder *none = gnm_style_border_none ();
177 GnmColor *nc;
179 if (color == none->color) {
180 style_color_unref (color);
181 return;
184 nc = none->color;
185 none->color = 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
197 GnmBorder *
198 gnm_style_border_fetch (GnmStyleBorderType line_type,
199 GnmColor *color,
200 GnmStyleBorderOrientation orientation)
202 GnmBorder *border;
203 GnmBorder key;
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;
218 key.color = color;
220 if (border_hash) {
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);
226 } else
227 border_hash = g_hash_table_new (style_border_hash,
228 style_border_equal);
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;
236 } else {
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);
242 return border;
245 gboolean
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;
253 gint
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)
260 return 0;
262 return style_border_data [line_type].width;
265 GnmStyleBorderOrientation
266 gnm_style_border_get_orientation (GnmStyleBorderLocation type)
268 switch (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:
277 default:
278 return GNM_STYLE_BORDER_HORIZONTAL;
283 * gnm_style_border_ref:
284 * @border: (nullable): #GnmBorder
286 * Returns: (transfer full): a reference to @border
288 GnmBorder *
289 gnm_style_border_ref (GnmBorder *border)
291 /* NULL is ok */
292 if (border != NULL) {
293 ++border->ref_count;
294 if (0) g_printerr ("style border ref: %p [color=%p]\n", border, border->color);
296 return border;
300 * gnm_style_border_unref:
301 * @border: (transfer full) (nullable): #GnmBorder
303 void
304 gnm_style_border_unref (GnmBorder *border)
306 if (border == NULL)
307 return;
309 g_return_if_fail (border->ref_count > 0);
311 if (0) g_printerr ("style border unref: %p\n", border);
313 border->ref_count--;
314 if (border->ref_count != 0)
315 return;
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;
329 g_free (border);
332 static void
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",
338 (void *)border,
339 border->color,
340 border->line_type,
341 border->ref_count);
345 * gnm_border_shutdown: (skip)
347 void
348 gnm_border_shutdown (void)
350 if (border_none) {
351 if (border_none->ref_count == 1) {
352 style_color_unref (border_none->color);
353 g_free (border_none);
354 } else {
355 cb_border_leak (NULL, border_none, NULL);
357 border_none = NULL;
360 if (border_hash) {
361 g_hash_table_foreach (border_hash, cb_border_leak, NULL);
362 g_hash_table_destroy (border_hash);
363 border_hash = NULL;
367 GType
368 gnm_border_get_type (void)
370 static GType t = 0;
372 if (t == 0) {
373 t = g_boxed_type_register_static ("GnmBorder",
374 (GBoxedCopyFunc)gnm_style_border_ref,
375 (GBoxedFreeFunc)gnm_style_border_unref);
377 return t;
380 static gboolean
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;
396 else
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;
400 else
401 offsets [1][0] = 0;
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;
406 else
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;
410 else
411 offsets [1][1] = 0;
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;
416 else
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;
420 else
421 offsets [0][0]= 0;
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;
426 else
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;
430 else
431 offsets [0][1] = 0;
432 return TRUE;
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;
453 } else {
454 /* pull outwards */
455 if (gnm_style_border_is_blank (sr->top [col-1])) {
456 int offset = 0;
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;
461 if (offset < tmp)
462 offset = tmp;
464 offsets [0][0] = -dir * offset;
467 if (gnm_style_border_is_blank (sr->top [col+1])) {
468 int offset = 0;
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;
473 if (offset < tmp)
474 offset = tmp;
476 offsets [0][1] = dir * offset;
479 return FALSE;
482 static gboolean
483 style_border_vmargins (GnmBorder const * const * prev_vert,
484 GnmStyleRow const *sr, int col,
485 int offsets [2][2])
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;
499 else
500 offsets [1][0] = 0;
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;
506 else
507 offsets [1][1] = 0;
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;
513 else
514 offsets [0][0] = 0;
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;
520 else
521 offsets [0][1] = 0;
522 return TRUE;
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)
536 offsets [0][0] = 1;
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)
544 offsets [0][1] = -1;
545 } else {
546 /* pull inwards */
547 int offset = 0;
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;
552 if (offset < tmp)
553 offset = tmp;
555 offsets [0][0] = offset;
557 offset = 0;
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;
562 if (offset < tmp)
563 offset = tmp;
565 offsets [0][1] = -offset;
567 return FALSE;
570 void
571 gnm_style_border_set_dash (GnmStyleBorderType const i,
572 cairo_t *context)
574 int w;
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;
581 if (w == 0)
582 w = 1;
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);
590 } else
591 cairo_set_dash (context, NULL, 0, 0);
594 static inline gboolean
595 style_border_set_gtk (GnmBorder const * const border,
596 cairo_t *context)
598 if (border == NULL)
599 return FALSE;
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));
604 return TRUE;
607 static inline void
608 print_hline_gtk (cairo_t *context,
609 double x1, double x2, double y, int width)
611 if (width == 0 || width % 2)
612 y += .5;
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);
620 static inline void
621 print_vline_gtk (cairo_t *context,
622 double x, double y1, double y2, int width, int dir)
624 if (width == 0 || width % 2)
625 x += .5*dir;
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.
639 void
640 gnm_style_borders_row_draw (GnmBorder const * const * prev_vert,
641 GnmStyleRow const *sr,
642 cairo_t *cr,
643 int x, int y1, int y2,
644 int *colwidths,
645 gboolean draw_vertical, int dir)
647 int o[2][2];
648 int col, next_x = x;
649 GnmBorder const *border;
651 cairo_save (cr);
653 for (col = sr->start_col; col <= sr->end_col ; col++, x = next_x) {
655 if (colwidths[col] == -1)
656 continue;
657 next_x = x + dir * colwidths[col];
659 border = sr->top [col];
661 if (style_border_set_gtk (border, cr)) {
662 double y = y1;
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.,
666 border->width);
667 ++y;
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);
675 if (!draw_vertical)
676 continue;
679 border = sr->vertical [col];
680 if (style_border_set_gtk (border, cr)) {
681 double x1 = x;
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);
685 x1 += 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);
692 if (draw_vertical) {
693 border = sr->vertical [col];
694 if (style_border_set_gtk (border, cr)) {
695 double x1 = x;
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);
699 x1 += 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);
707 cairo_restore (cr);
710 void
711 gnm_style_border_draw_diag (GnmStyle const *style,
712 cairo_t *cr,
713 int x1, int y1, int x2, int y2)
715 GnmBorder const *diag;
717 cairo_save (cr);
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);
725 cairo_stroke (cr);
726 cairo_move_to (cr, x1+ 3., y1+1.5);
727 cairo_line_to (cr, x2- .5, y2-2.);
728 } else {
729 cairo_move_to (cr, x1+.5, y1+.5);
730 cairo_line_to (cr, x2+.5, y2+.5);
732 cairo_stroke (cr);
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);
741 cairo_stroke (cr);
742 cairo_move_to (cr, x1+3., y2- .5);
743 cairo_line_to (cr, x2- .5, y1+3.);
744 } else {
745 cairo_move_to (cr, x1+.5, y2+.5);
746 cairo_line_to (cr, x2+.5, y1+.5);
748 cairo_stroke (cr);
751 cairo_restore (cr);
754 void
755 gnm_style_borders_row_print_gtk (GnmBorder const * const * prev_vert,
756 GnmStyleRow const *sr,
757 cairo_t *context,
758 double x, double y1, double y2,
759 Sheet const *sheet,
760 gboolean draw_vertical, int dir)
762 int o[2][2], col;
763 double next_x = x;
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);
774 if (!cri->visible)
775 continue;
776 next_x = x + dir * cri->size_pts * hscale;
778 border = sr->top [col];
780 if (style_border_set_gtk (border, context)) {
781 double y = y1;
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.,
785 border->width);
786 ++y;
789 print_hline_gtk (context, x + o[0][0],
790 next_x + o[0][1] + dir, y, border->width);
793 if (!draw_vertical)
794 continue;
797 border = sr->vertical [col];
798 if (style_border_set_gtk (border, context)) {
799 double x1 = x;
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);
803 x1 += dir;
805 print_vline_gtk (context, x1, y1 + o[0][0],
806 y2 + o[0][1] + 1., border->width, dir);
809 if (draw_vertical) {
810 border = sr->vertical [col];
811 if (style_border_set_gtk (border, context)) {
812 double x1 = x;
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);
816 x1 += 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);
827 void
828 gnm_style_border_print_diag_gtk (GnmStyle const *style,
829 cairo_t *context,
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.);
846 } else {
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.);
862 } else {
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);