1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * gnm-style.c: Storing a style
6 * Michael Meeks <mmeeks@gnu.org>
7 * Almer S. Tigelaar <almer@gnome.org>
8 * Jody Goldberg <jody@gnome.org>
9 * Morten Welinder <terra@gnome.org>
11 #include <gnumeric-config.h>
15 #include "gnm-style-impl.h"
16 #include "sheet-style.h"
17 #include "style-conditions.h"
19 #include "application.h"
20 #include "parse-util.h"
25 #include "gnumeric-conf.h"
26 #include <goffice/goffice.h>
30 #ifndef USE_MSTYLE_POOL
31 #define USE_MSTYLE_POOL 1
35 /* Memory pool for GnmStyles. */
36 static GOMemChunk
*gnm_style_pool
;
37 #define CHUNK_ALLOC(T,p) ((T*)go_mem_chunk_alloc (p))
38 #define CHUNK_ALLOC0(T,p) ((T*)go_mem_chunk_alloc0 (p))
39 #define CHUNK_FREE(p,v) go_mem_chunk_free ((p), (v))
41 #define CHUNK_ALLOC(T,c) g_new (T,1)
42 #define CHUNK_ALLOC0(T,c) g_new0 (T,1)
43 #define CHUNK_FREE(p,v) g_free ((v))
46 #define UNROLLED_FOR(init_,cond_,step_,code_) \
49 if (cond_) { code_; step_; \
50 if (cond_) { code_; step_; \
51 if (cond_) { code_; step_; \
52 if (cond_) { code_; step_; \
53 if (cond_) { code_; step_; \
54 if (cond_) { code_; step_; \
55 if (cond_) { code_; step_; \
56 if (cond_) { code_; step_; \
57 if (cond_) { code_; step_; \
58 if (cond_) { code_; step_; \
59 if (cond_) { code_; step_; \
60 if (cond_) { code_; step_; \
61 if (cond_) { code_; step_; \
62 if (cond_) { code_; step_; \
63 if (cond_) { code_; step_; \
64 if (cond_) { code_; step_; \
65 if (cond_) { code_; step_; \
66 if (cond_) { code_; step_; \
67 if (cond_) { code_; step_; \
68 if (cond_) { code_; step_; \
69 if (cond_) { code_; step_; \
70 if (cond_) { code_; step_; \
71 if (cond_) { code_; step_; \
72 if (cond_) { code_; step_; \
73 if (cond_) { code_; step_; \
74 if (cond_) { code_; step_; \
75 if (cond_) { code_; step_; \
76 if (cond_) { code_; step_; \
77 if (cond_) { code_; step_; \
78 if (cond_) { code_; step_; \
79 if (cond_) { code_; step_; \
80 if (cond_) { code_; step_; \
81 if (cond_) { code_; step_; \
82 if (cond_) { code_; step_; \
83 if (cond_) { code_; step_; \
84 if (cond_) { code_; step_; \
85 if (cond_) { code_; step_; \
86 if (cond_) { code_; step_; \
87 if (cond_) { code_; step_; \
88 if (cond_) { code_; step_; \
89 if (cond_) { code_; step_; \
90 if (cond_) { code_; step_; \
91 if (cond_) { code_; step_; \
92 if (cond_) { code_; step_; \
93 if (cond_) { code_; step_; \
94 if (cond_) { code_; step_; \
95 if (cond_) { code_; step_; \
96 if (cond_) { code_; step_; \
97 if (cond_) { code_; step_; \
98 if (cond_) { code_; step_; \
99 g_assert_not_reached (); \
100 }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} \
105 static char const * const
106 gnm_style_element_name
[MSTYLE_ELEMENT_MAX
] = {
113 "Border.RevDiagonal",
121 "Font.Strikethrough",
138 /* Some ref/link count debugging */
140 #define d(arg) g_printerr arg
142 #define d(arg) do { } while (0)
146 clear_conditional_merges (GnmStyle
*style
)
148 if (style
->cond_styles
) {
149 unsigned i
= style
->cond_styles
->len
;
151 gnm_style_unref (g_ptr_array_index (style
->cond_styles
, i
));
152 g_ptr_array_free (style
->cond_styles
, TRUE
);
153 style
->cond_styles
= NULL
;
157 #define MIX(H) do { \
158 H *= G_GUINT64_CONSTANT(123456789012345); \
163 gnm_style_update (GnmStyle
*style
)
168 g_return_if_fail (style
->changed
);
172 clear_conditional_merges (style
);
173 if (elem_is_set (style
, MSTYLE_CONDITIONS
) && style
->conditions
)
174 style
->cond_styles
= gnm_style_conditions_overlay (style
->conditions
, style
);
176 /* ---------------------------------------- */
178 if (elem_is_set (style
, MSTYLE_COLOR_BACK
)) {
179 if (!style
->color
.back
->is_auto
)
180 hash
^= GPOINTER_TO_UINT (style
->color
.back
);
186 if (elem_is_set (style
, MSTYLE_COLOR_PATTERN
)) {
187 if (!style
->color
.pattern
->is_auto
)
188 hash
^= GPOINTER_TO_UINT (style
->color
.pattern
);
194 if (elem_is_set (style
, MSTYLE_FONT_COLOR
)) {
195 if (!style
->color
.font
->is_auto
)
196 hash
^= GPOINTER_TO_UINT (style
->color
.font
);
202 for (i
= MSTYLE_BORDER_TOP
; i
<= MSTYLE_BORDER_DIAGONAL
; i
++) {
203 if (elem_is_set (style
, i
))
204 hash
^= GPOINTER_TO_UINT (style
->borders
[i
- MSTYLE_BORDER_TOP
]);
210 if (elem_is_set (style
, MSTYLE_PATTERN
))
211 hash
^= style
->pattern
;
214 if (elem_is_set (style
, MSTYLE_FONT_NAME
))
215 hash
^= GPOINTER_TO_UINT (style
->font_detail
.name
);
218 if (elem_is_set (style
, MSTYLE_FONT_BOLD
))
219 hash
^= (style
->font_detail
.bold
? 1 : 2);
222 if (elem_is_set (style
, MSTYLE_FONT_ITALIC
))
223 hash
^= (style
->font_detail
.italic
? 1 : 2);
226 if (elem_is_set (style
, MSTYLE_FONT_UNDERLINE
))
227 hash
^= (style
->font_detail
.underline
? 1 : 2);
230 if (elem_is_set (style
, MSTYLE_FONT_STRIKETHROUGH
))
231 hash
^= (style
->font_detail
.strikethrough
? 1 : 2);
234 if (elem_is_set (style
, MSTYLE_FONT_SCRIPT
))
235 hash
^= (style
->font_detail
.script
+ 0x100);
238 if (elem_is_set (style
, MSTYLE_FONT_SIZE
))
239 hash
^= ((int)(style
->font_detail
.size
* 97));
242 if (elem_is_set (style
, MSTYLE_FORMAT
))
243 hash
^= GPOINTER_TO_UINT (style
->format
);
246 if (elem_is_set (style
, MSTYLE_ALIGN_H
))
247 hash
^= (style
->h_align
+ 0x100);
250 if (elem_is_set (style
, MSTYLE_ALIGN_V
))
251 hash
^= (style
->v_align
+ 0x100);
254 if (elem_is_set (style
, MSTYLE_INDENT
))
255 hash
^= style
->indent
;
258 if (elem_is_set (style
, MSTYLE_ROTATION
))
259 hash
^= style
->rotation
;
262 if (elem_is_set (style
, MSTYLE_TEXT_DIR
))
263 hash
^= (style
->text_dir
+ 0x100);
266 if (elem_is_set (style
, MSTYLE_WRAP_TEXT
))
267 hash
^= (style
->wrap_text
? 1 : 2);
270 if (elem_is_set (style
, MSTYLE_SHRINK_TO_FIT
))
271 hash
^= (style
->shrink_to_fit
? 1 : 2);
274 if (elem_is_set (style
, MSTYLE_CONTENTS_LOCKED
))
275 hash
^= (style
->contents_locked
? 1 : 2);
278 if (elem_is_set (style
, MSTYLE_CONTENTS_HIDDEN
))
279 hash
^= (style
->contents_hidden
? 1 : 2);
282 style
->hash_key_xl
= (guint32
)hash
;
284 /* From here on, fields are not in MS XL */
286 if (elem_is_set (style
, MSTYLE_VALIDATION
)) {
288 * The hash used must not depend on the expressions inside
291 hash
^= (style
->validation
!= NULL
? 1 : 2);
295 if (elem_is_set (style
, MSTYLE_HLINK
))
296 hash
^= GPOINTER_TO_UINT (style
->hlink
);
299 if (elem_is_set (style
, MSTYLE_INPUT_MSG
))
300 hash
^= GPOINTER_TO_UINT (style
->input_msg
);
303 if (elem_is_set (style
, MSTYLE_CONDITIONS
)) {
305 * The hash used must not depend on the expressions inside
308 hash
^= style
->conditions
309 ? gnm_style_conditions_hash (style
->conditions
)
314 style
->hash_key
= (guint32
)hash
;
316 if (G_UNLIKELY (style
->set
== 0)) {
318 * gnm_style_new and gnm_style_dup both assume that the
319 * correct hash values (both of them) for the empty style
322 g_assert (style
->hash_key
== 0);
323 g_assert (style
->hash_key_xl
== 0);
330 gnm_style_hash_XL (gconstpointer style
)
332 if (((GnmStyle
const *)style
)->changed
)
333 gnm_style_update ((GnmStyle
*)style
);
334 return ((GnmStyle
const *)style
)->hash_key_xl
;
338 gnm_style_hash (gconstpointer style
)
340 if (((GnmStyle
const *)style
)->changed
)
341 gnm_style_update ((GnmStyle
*)style
);
342 return ((GnmStyle
const *)style
)->hash_key
;
345 #define ELEM_IS_EQ(a,b,elem) \
346 (elem == MSTYLE_COLOR_BACK \
347 ? a->color.back == b->color.back || (a->color.back->is_auto && b->color.back->is_auto) \
348 : (elem == MSTYLE_COLOR_PATTERN \
349 ? a->color.pattern == b->color.pattern || (a->color.pattern->is_auto && b->color.pattern->is_auto) \
350 : (elem >= MSTYLE_BORDER_TOP && elem <= MSTYLE_BORDER_DIAGONAL) \
351 ? a->borders[elem - MSTYLE_BORDER_TOP] == b->borders[elem - MSTYLE_BORDER_TOP] \
352 : (elem == MSTYLE_PATTERN \
353 ? a->pattern == b->pattern \
354 : (elem == MSTYLE_FONT_COLOR \
355 ? a->color.font == b->color.font || (a->color.font->is_auto && b->color.font->is_auto) \
356 : (elem == MSTYLE_FONT_NAME \
357 ? a->font_detail.name == b->font_detail.name \
358 : (elem == MSTYLE_FONT_BOLD \
359 ? a->font_detail.bold == b->font_detail.bold \
360 : (elem == MSTYLE_FONT_ITALIC \
361 ? a->font_detail.italic == b->font_detail.italic \
362 : (elem == MSTYLE_FONT_UNDERLINE \
363 ? a->font_detail.underline == b->font_detail.underline \
364 : (elem == MSTYLE_FONT_STRIKETHROUGH \
365 ? a->font_detail.strikethrough == b->font_detail.strikethrough \
366 : (elem == MSTYLE_FONT_SCRIPT \
367 ? a->font_detail.script == b->font_detail.script \
368 : (elem == MSTYLE_FONT_SIZE \
369 ? a->font_detail.size == b->font_detail.size \
370 : (elem == MSTYLE_FORMAT \
371 ? a->format == b->format \
372 : (elem == MSTYLE_ALIGN_V \
373 ? a->v_align == b->v_align \
374 : (elem == MSTYLE_ALIGN_H \
375 ? a->h_align == b->h_align \
376 : (elem == MSTYLE_INDENT \
377 ? a->indent == b->indent \
378 : (elem == MSTYLE_ROTATION \
379 ? a->rotation == b->rotation \
380 : (elem == MSTYLE_TEXT_DIR \
381 ? a->text_dir == b->text_dir \
382 : (elem == MSTYLE_WRAP_TEXT \
383 ? a->wrap_text == b->wrap_text \
384 : (elem == MSTYLE_SHRINK_TO_FIT \
385 ? a->shrink_to_fit == b->shrink_to_fit \
386 : (elem == MSTYLE_CONTENTS_LOCKED \
387 ? a->contents_locked == b->contents_locked \
388 : (elem == MSTYLE_CONTENTS_HIDDEN \
389 ? a->contents_hidden == b->contents_hidden \
390 : (elem == MSTYLE_VALIDATION \
391 ? a->validation == b->validation \
392 : (elem == MSTYLE_HLINK \
393 ? a->hlink == b->hlink \
394 : (elem == MSTYLE_INPUT_MSG \
395 ? a->input_msg == b->input_msg \
396 : (elem == MSTYLE_CONDITIONS \
397 ? (a->conditions == b->conditions || \
398 (a->conditions && b->conditions && \
399 gnm_style_conditions_equal (a->conditions, b->conditions))) \
400 : FALSE)))))))))))))))))))))))))
403 * Note: the above is suboptimal for validation, hlink, input_msg.
405 * We are comparing pointers (which at least safely matches what we do
406 * with the hash), but I think we want proper equality.
410 elem_is_eq (GnmStyle
const *a
, GnmStyle
const *b
, GnmStyleElement elem
)
412 return ELEM_IS_EQ (a
, b
, elem
);
416 elem_assign_contents (GnmStyle
*dst
, GnmStyle
const *src
, GnmStyleElement elem
)
419 g_return_if_fail (src
!= dst
);
420 g_return_if_fail (elem_is_set (src
, elem
));
423 case MSTYLE_COLOR_BACK
: style_color_ref (dst
->color
.back
= src
->color
.back
); return;
424 case MSTYLE_COLOR_PATTERN
: style_color_ref (dst
->color
.pattern
= src
->color
.pattern
); return;
425 case MSTYLE_ANY_BORDER
:
426 elem
-= MSTYLE_BORDER_TOP
;
427 gnm_style_border_ref (dst
->borders
[elem
] = src
->borders
[elem
]);
429 case MSTYLE_PATTERN
: dst
->pattern
= src
->pattern
; return;
430 case MSTYLE_FONT_COLOR
: style_color_ref (dst
->color
.font
= src
->color
.font
); return;
431 case MSTYLE_FONT_NAME
: go_string_ref (dst
->font_detail
.name
= src
->font_detail
.name
); return;
432 case MSTYLE_FONT_BOLD
: dst
->font_detail
.bold
= src
->font_detail
.bold
; return;
433 case MSTYLE_FONT_ITALIC
: dst
->font_detail
.italic
= src
->font_detail
.italic
; return;
434 case MSTYLE_FONT_UNDERLINE
: dst
->font_detail
.underline
= src
->font_detail
.underline
; return;
435 case MSTYLE_FONT_STRIKETHROUGH
: dst
->font_detail
.strikethrough
= src
->font_detail
.strikethrough
; return;
436 case MSTYLE_FONT_SCRIPT
: dst
->font_detail
.script
= src
->font_detail
.script
; return;
437 case MSTYLE_FONT_SIZE
: dst
->font_detail
.size
= src
->font_detail
.size
; return;
438 case MSTYLE_FORMAT
: go_format_ref (dst
->format
= src
->format
); return;
439 case MSTYLE_ALIGN_V
: dst
->v_align
= src
->v_align
; return;
440 case MSTYLE_ALIGN_H
: dst
->h_align
= src
->h_align
; return;
441 case MSTYLE_INDENT
: dst
->indent
= src
->indent
; return;
442 case MSTYLE_ROTATION
: dst
->rotation
= src
->rotation
; return;
443 case MSTYLE_TEXT_DIR
: dst
->text_dir
= src
->text_dir
; return;
444 case MSTYLE_WRAP_TEXT
: dst
->wrap_text
= src
->wrap_text
; return;
445 case MSTYLE_SHRINK_TO_FIT
: dst
->shrink_to_fit
= src
->shrink_to_fit
; return;
446 case MSTYLE_CONTENTS_LOCKED
: dst
->contents_locked
= src
->contents_locked
; return;
447 case MSTYLE_CONTENTS_HIDDEN
: dst
->contents_hidden
= src
->contents_hidden
; return;
448 case MSTYLE_VALIDATION
:
449 if ((dst
->validation
= src
->validation
))
450 gnm_validation_ref (dst
->validation
);
453 if ((dst
->hlink
= src
->hlink
))
454 g_object_ref (dst
->hlink
);
456 case MSTYLE_INPUT_MSG
:
457 if ((dst
->input_msg
= src
->input_msg
))
458 g_object_ref (dst
->input_msg
);
460 case MSTYLE_CONDITIONS
:
461 if ((dst
->conditions
= src
->conditions
))
462 g_object_ref (dst
->conditions
);
470 elem_clear_contents (GnmStyle
*style
, GnmStyleElement elem
)
473 g_return_if_fail (style
!= NULL
);
475 if (!elem_is_set (style
, elem
))
479 case MSTYLE_COLOR_BACK
: style_color_unref (style
->color
.back
); return;
480 case MSTYLE_COLOR_PATTERN
: style_color_unref (style
->color
.pattern
); return;
481 case MSTYLE_ANY_BORDER
:
482 gnm_style_border_unref (style
->borders
[elem
- MSTYLE_BORDER_TOP
]);
484 case MSTYLE_FONT_COLOR
: style_color_unref (style
->color
.font
); return;
485 case MSTYLE_FONT_NAME
: go_string_unref (style
->font_detail
.name
); return;
486 case MSTYLE_FORMAT
: go_format_unref (style
->format
); return;
487 case MSTYLE_VALIDATION
:
488 if (style
->validation
)
489 gnm_validation_unref (style
->validation
);
493 g_object_unref (style
->hlink
);
495 case MSTYLE_INPUT_MSG
:
496 if (style
->input_msg
)
497 g_object_unref (style
->input_msg
);
499 case MSTYLE_CONDITIONS
:
500 if (style
->conditions
) {
501 clear_conditional_merges (style
);
502 g_object_unref (style
->conditions
);
511 * gnm_style_find_conflicts :
512 * @accum: accumulator #GnmStyle
513 * @overlay: #GnmStyle
516 * Copy any items from @overlay that do not conflict with the values in @accum.
517 * If an element had a previous conflict (flagged via @conflicts) it is ignored.
519 * Returns @conflicts with any new conflicts added.
522 gnm_style_find_conflicts (GnmStyle
*accum
, GnmStyle
const *overlay
,
523 unsigned int conflicts
)
527 g_assert (MSTYLE_ELEMENT_MAX
<= CHAR_BIT
* sizeof (conflicts
));
529 for (i
= 0; i
< MSTYLE_ELEMENT_MAX
; i
++) {
530 if (conflicts
& (1u << i
) || !elem_is_set (overlay
, i
)) {
532 } else if (!elem_is_set (accum
, i
)) {
533 elem_assign_contents (accum
, overlay
, i
);
535 elem_changed (accum
, i
);
536 } else if (!elem_is_eq (accum
, overlay
, i
))
537 conflicts
|= (1u << i
);
544 * gnm_style_find_differences:
547 * @relax_sheet: if %TRUE, ignore differences solely caused by being linked into different sheets.
549 * Determine how two fully-qualified styles differ.
551 * Returns differences as a bitset of #GnmStyleElement.
554 gnm_style_find_differences (GnmStyle
const *a
, GnmStyle
const *b
,
555 gboolean relax_sheet
)
558 unsigned int diffs
= 0;
560 g_assert (MSTYLE_ELEMENT_MAX
<= CHAR_BIT
* sizeof (diffs
));
562 for (i
= 0; i
< MSTYLE_ELEMENT_MAX
; i
++) {
563 if (elem_is_set (a
, i
) != elem_is_set (b
, i
) ||
564 (elem_is_set (a
, i
) && !elem_is_eq (a
, b
, i
)))
569 if (a
->hlink
&& b
->hlink
&&
570 gnm_hlink_equal (a
->hlink
, b
->hlink
, relax_sheet
))
571 diffs
&= ~(1u << MSTYLE_HLINK
);
573 // FIXME: Validations
583 gnm_style_clear_pango (GnmStyle
*style
)
585 if (style
->pango_attrs
) {
586 pango_attr_list_unref (style
->pango_attrs
);
587 style
->pango_attrs
= NULL
;
593 gnm_style_clear_font (GnmStyle
*style
)
596 gnm_font_unref (style
->font
);
599 g_clear_object (&style
->font_context
);
605 * Caller is responsible for unrefing the result.
607 * Returns a new style with _no_ elements set.
612 GnmStyle
*style
= CHUNK_ALLOC0 (GnmStyle
, gnm_style_pool
);
614 style
->ref_count
= 1;
615 style
->link_count
= 0;
616 style
->linked_sheet
= NULL
;
617 style
->pango_attrs
= NULL
;
619 style
->validation
= NULL
;
621 style
->set
= style
->changed
= 0;
622 style
->validation
= NULL
;
624 style
->input_msg
= NULL
;
625 style
->conditions
= NULL
;
627 d(("new %p\n", style
));
633 * gnm_style_new_default:
635 * Caller is responsible for unrefing the result.
637 * Return value: a new style initialized to the default state.
640 gnm_style_new_default (void)
642 GnmStyle
*new_style
= gnm_style_new ();
645 gnm_style_set_font_name (new_style
, gnm_conf_get_core_defaultfont_name ());
646 gnm_style_set_font_size (new_style
, gnm_conf_get_core_defaultfont_size ());
647 gnm_style_set_font_bold (new_style
, gnm_conf_get_core_defaultfont_bold ());
648 gnm_style_set_font_italic (new_style
, gnm_conf_get_core_defaultfont_italic ());
650 gnm_style_set_format (new_style
, go_format_general ());
651 gnm_style_set_align_v (new_style
, GNM_VALIGN_BOTTOM
);
652 gnm_style_set_align_h (new_style
, GNM_HALIGN_GENERAL
);
653 gnm_style_set_indent (new_style
, 0);
654 gnm_style_set_rotation (new_style
, 0);
655 gnm_style_set_text_dir (new_style
, GNM_TEXT_DIR_CONTEXT
);
656 gnm_style_set_wrap_text (new_style
, FALSE
);
657 gnm_style_set_shrink_to_fit (new_style
, FALSE
);
658 gnm_style_set_contents_locked (new_style
, TRUE
);
659 gnm_style_set_contents_hidden (new_style
, FALSE
);
660 gnm_style_set_font_uline (new_style
, UNDERLINE_NONE
);
661 gnm_style_set_font_strike (new_style
, FALSE
);
662 gnm_style_set_font_script (new_style
, GO_FONT_SCRIPT_STANDARD
);
664 gnm_style_set_validation (new_style
, NULL
);
665 gnm_style_set_hlink (new_style
, NULL
);
666 gnm_style_set_input_msg (new_style
, NULL
);
667 gnm_style_set_conditions (new_style
, NULL
);
669 gnm_style_set_font_color (new_style
, style_color_black ());
670 gnm_style_set_back_color (new_style
, style_color_auto_back ());
671 gnm_style_set_pattern_color (new_style
, style_color_black ());
673 for (i
= MSTYLE_BORDER_TOP
; i
<= MSTYLE_BORDER_DIAGONAL
; ++i
)
674 gnm_style_set_border (new_style
, i
,
675 gnm_style_border_ref (gnm_style_border_none ()));
676 gnm_style_set_pattern (new_style
, 0);
682 gnm_style_dup (GnmStyle
const *src
)
684 GnmStyle
*new_style
= CHUNK_ALLOC0 (GnmStyle
, gnm_style_pool
);
687 new_style
->ref_count
= 1;
688 for (i
= 0; i
< MSTYLE_ELEMENT_MAX
; i
++)
689 if (elem_is_set (src
, i
)) {
690 elem_assign_contents (new_style
, src
, i
);
691 elem_set (new_style
, i
);
692 elem_changed (new_style
, i
);
695 if ((new_style
->pango_attrs
= src
->pango_attrs
)) {
696 pango_attr_list_ref (new_style
->pango_attrs
);
697 new_style
->pango_attrs_zoom
= src
->pango_attrs_zoom
;
700 if ((new_style
->font
= src
->font
)) {
701 gnm_font_ref (new_style
->font
);
702 new_style
->font_context
= g_object_ref (src
->font_context
);
705 d(("dup %p\n", new_style
));
710 * gnm_style_new_merged :
712 * @overlay: #GnmStyle
714 * A new GnmStyle that contains any elements of @overlay that are set, and uses
715 * @base for anything that is not set in @overlay.
717 * Returns: (transfer full): A ref to a new GnmStyle.
720 gnm_style_new_merged (GnmStyle
const *base
, GnmStyle
const *overlay
)
722 GnmStyle
*new_style
= CHUNK_ALLOC0 (GnmStyle
, gnm_style_pool
);
725 new_style
->ref_count
= 1;
726 for (i
= 0; i
< MSTYLE_ELEMENT_MAX
; i
++) {
727 if (elem_is_set (overlay
, i
))
728 elem_assign_contents (new_style
, overlay
, i
);
729 else if (elem_is_set (base
, i
))
730 elem_assign_contents (new_style
, base
, i
);
733 elem_set (new_style
, i
);
734 elem_changed (new_style
, i
);
736 d(("copy merge %p\n", new_style
));
741 gnm_style_ref (GnmStyle
const *style
)
743 g_return_if_fail (style
!= NULL
);
744 g_return_if_fail (style
->ref_count
> 0);
746 ((GnmStyle
*)style
)->ref_count
++;
747 d(("ref %p = %d\n", style
, style
->ref_count
));
752 * @style: #GnmStyle const
754 * Unrefs and _potentially frees_ @style.
755 * Takes a _const_ pointer to facilitate life cycles. The const indicates that
756 * the content can not be changed, mainly when handling styles that are in the
760 gnm_style_unref (GnmStyle
const *style
)
762 g_return_if_fail (style
!= NULL
);
763 g_return_if_fail (style
->ref_count
> 0);
765 d(("unref %p = %d\n", style
, style
->ref_count
-1));
766 if (((GnmStyle
*)style
)->ref_count
-- <= 1) {
767 GnmStyle
*unconst
= (GnmStyle
*)style
;
770 g_return_if_fail (style
->link_count
== 0);
771 g_return_if_fail (style
->linked_sheet
== NULL
);
773 for (i
= 0; i
< MSTYLE_ELEMENT_MAX
; i
++)
774 elem_clear_contents (unconst
, i
);
776 clear_conditional_merges (unconst
);
777 gnm_style_clear_pango (unconst
);
778 gnm_style_clear_font (unconst
);
781 if (style
->deps
->len
> 0)
782 g_warning ("Leftover style deps!");
783 g_ptr_array_free (style
->deps
, TRUE
);
786 CHUNK_FREE (gnm_style_pool
, unconst
);
791 gnm_style_get_type (void)
796 t
= g_boxed_type_register_static ("GnmStyle",
797 (GBoxedCopyFunc
)gnm_style_ref
,
798 (GBoxedFreeFunc
)gnm_style_unref
);
804 * Replace auto pattern color in style with sheet's auto pattern color.
805 * make_copy tells if we are allowed to modify the style in place or we must
809 link_pattern_color (GnmStyle
*style
, GnmColor
*auto_color
, gboolean make_copy
)
811 GnmColor
*pattern_color
= style
->color
.pattern
;
813 if (pattern_color
->is_auto
&& auto_color
!= pattern_color
) {
814 style_color_ref (auto_color
);
816 GnmStyle
*orig
= style
;
817 style
= gnm_style_dup (style
);
818 gnm_style_unref (orig
);
820 gnm_style_set_pattern_color (style
, auto_color
);
826 * Replace auto border colors in style with sheet's auto pattern
827 * color. (pattern is *not* a typo.)
828 * make_copy tells if we are allowed to modify the style in place or we must
831 * FIXME: We conjecture that XL color 64 in border should change with the
832 * pattern, but not color 127. That distinction is not yet represented in
833 * our data structures.
836 link_border_colors (GnmStyle
*style
, GnmColor
*auto_color
, gboolean make_copy
)
840 for (i
= MSTYLE_BORDER_TOP
; i
<= MSTYLE_BORDER_DIAGONAL
; ++i
) {
841 if (elem_is_set (style
, i
)) {
843 style
->borders
[i
- MSTYLE_BORDER_TOP
];
849 color
= border
->color
;
850 if (color
->is_auto
&& auto_color
!= color
) {
851 GnmBorder
*new_border
;
852 GnmStyleBorderOrientation orientation
;
855 case MSTYLE_BORDER_LEFT
:
856 case MSTYLE_BORDER_RIGHT
:
857 orientation
= GNM_STYLE_BORDER_VERTICAL
;
859 case MSTYLE_BORDER_REV_DIAGONAL
:
860 case MSTYLE_BORDER_DIAGONAL
:
861 orientation
= GNM_STYLE_BORDER_DIAGONAL
;
863 case MSTYLE_BORDER_TOP
:
864 case MSTYLE_BORDER_BOTTOM
:
866 orientation
= GNM_STYLE_BORDER_HORIZONTAL
;
869 style_color_ref (auto_color
);
870 new_border
= gnm_style_border_fetch (
871 border
->line_type
, auto_color
,
875 GnmStyle
*orig
= style
;
876 style
= gnm_style_dup (style
);
877 gnm_style_unref (orig
);
880 gnm_style_set_border (style
, i
, new_border
);
888 gnm_style_linked_sheet_changed (GnmStyle
*style
)
890 Sheet
*sheet
= style
->linked_sheet
;
892 if (elem_is_set (style
, MSTYLE_VALIDATION
) &&
894 gnm_validation_get_sheet (style
->validation
) != sheet
) {
895 GnmValidation
*new_v
= gnm_validation_dup (style
->validation
);
896 gnm_validation_set_sheet (new_v
, sheet
);
897 gnm_style_set_validation (style
, new_v
);
900 if (elem_is_set (style
, MSTYLE_HLINK
) &&
902 gnm_hlink_get_sheet (style
->hlink
) != sheet
) {
903 GnmHLink
*new_l
= gnm_hlink_dup (style
->hlink
);
904 gnm_hlink_set_sheet (new_l
, sheet
);
905 gnm_style_set_hlink (style
, new_l
);
908 if (elem_is_set (style
, MSTYLE_CONDITIONS
) &&
910 gnm_style_conditions_get_sheet (style
->conditions
) != sheet
) {
911 GnmStyleConditions
*new_c
= gnm_style_conditions_dup (style
->conditions
);
912 gnm_style_conditions_set_sheet (new_c
, sheet
);
913 gnm_style_set_conditions (style
, new_c
);
918 * gnm_style_link_sheet :
922 * ABSORBS a reference to the style and sets the link count to 1.
924 * Where auto pattern color occurs in the style (it may for pattern and
925 * borders), it is replaced with the sheet's auto pattern color. We make
926 * sure that we do not modify the style which was passed in to us, but also
927 * that we don't copy more than once. The final argument to the
928 * link_xxxxx_color functions tell whether or not to copy.
931 gnm_style_link_sheet (GnmStyle
*style
, Sheet
*sheet
)
933 GnmColor
*auto_color
;
934 gboolean style_is_orig
= TRUE
;
936 if (style
->linked_sheet
!= NULL
) {
937 GnmStyle
*orig
= style
;
938 style
= gnm_style_dup (style
);
939 gnm_style_unref (orig
);
940 style_is_orig
= FALSE
;
943 g_return_val_if_fail (style
->linked_sheet
!= sheet
, style
);
946 g_return_val_if_fail (style
->link_count
== 0, style
);
947 g_return_val_if_fail (style
->linked_sheet
== NULL
, style
);
949 auto_color
= sheet_style_get_auto_pattern_color (sheet
);
950 if (elem_is_set (style
, MSTYLE_COLOR_PATTERN
))
951 style
= link_pattern_color (style
, auto_color
, style_is_orig
);
952 style
= link_border_colors (style
, auto_color
, style_is_orig
);
953 style_color_unref (auto_color
);
955 style
->linked_sheet
= sheet
;
956 style
->link_count
= 1;
958 gnm_style_linked_sheet_changed (style
);
960 d(("link sheet %p = 1\n", style
));
965 gnm_style_link (GnmStyle
*style
)
967 g_return_if_fail (style
->link_count
> 0);
970 d(("link %p = %d\n", style
, style
->link_count
));
974 gnm_style_link_multiple (GnmStyle
*style
, int count
)
976 g_return_if_fail (style
->link_count
> 0);
978 style
->link_count
+= count
;
979 d(("multiple link %p + %d = %d\n", style
, count
, style
->link_count
));
983 gnm_style_unlink (GnmStyle
*style
)
985 g_return_if_fail (style
->link_count
> 0);
987 d(("unlink %p = %d\n", style
, style
->link_count
-1));
988 if (style
->link_count
-- == 1) {
989 sheet_style_unlink (style
->linked_sheet
, style
);
990 style
->linked_sheet
= NULL
;
991 gnm_style_unref (style
);
996 gnm_style_eq (GnmStyle
const *a
, GnmStyle
const *b
)
1002 gnm_style_equal (GnmStyle
const *a
, GnmStyle
const *b
)
1008 if (a
->set
!= b
->set
|| !gnm_style_equal_XL (a
, b
))
1010 UNROLLED_FOR (i
= MSTYLE_VALIDATION
, i
< MSTYLE_ELEMENT_MAX
, i
++, {
1011 if (elem_is_set (a
, i
) && !ELEM_IS_EQ (a
, b
, i
))
1019 gnm_style_equal_XL (GnmStyle
const *a
, GnmStyle
const *b
)
1023 g_return_val_if_fail (a
!= NULL
, FALSE
);
1024 g_return_val_if_fail (b
!= NULL
, FALSE
);
1029 if ((a
->set
^ b
->set
) & ((1u << MSTYLE_VALIDATION
) - 1))
1032 UNROLLED_FOR (i
= MSTYLE_COLOR_BACK
, i
< MSTYLE_VALIDATION
, i
++, {
1033 if (elem_is_set (a
, i
) && !ELEM_IS_EQ (a
, b
, i
))
1040 * gnm_style_equal_elem:
1045 * Returns: %TRUE, if the two styles have the same contents for the
1046 * given element, either because neither have it set, or because both
1047 * have it set and to the same value.
1050 gnm_style_equal_elem (GnmStyle
const *a
, GnmStyle
const *b
, GnmStyleElement e
)
1052 if (elem_is_set (a
, e
))
1053 return elem_is_set (b
, e
) && elem_is_eq (a
, b
, e
);
1055 return !elem_is_set (b
, e
);
1060 #define CMP_TRY_NUMBER_RAW(a_,b_) \
1062 if ((a_) < (b_)) return -1; \
1063 if ((a_) > (b_)) return -1; \
1066 #define CMP_TRY_NUMBER(e_,f_) \
1068 if (elem_is_set (a, (e_))) \
1069 CMP_TRY_NUMBER_RAW(a->f_, b->f_); \
1072 #define CMP_TRY_COLOR(e_,f_) \
1074 if (elem_is_set (a, (e_))) { \
1075 CMP_TRY_NUMBER_RAW(a->f_->is_auto, b->f_->is_auto); \
1076 CMP_TRY_NUMBER_RAW(a->f_->go_color, b->f_->go_color); \
1081 * Ordering of GnmStyles. Apart from FIXMEs, this shouldn't change
1082 * from one run to the next.
1085 gnm_style_cmp (GnmStyle
const *a
, GnmStyle
const *b
)
1093 * Very quick comparison based on what is set. This also allows
1094 * us to check on one elem_is_set below.
1096 CMP_TRY_NUMBER_RAW (a
->set
, b
->set
);
1098 CMP_TRY_COLOR (MSTYLE_FONT_COLOR
, color
.font
);
1099 CMP_TRY_COLOR (MSTYLE_COLOR_BACK
, color
.back
);
1100 CMP_TRY_COLOR (MSTYLE_COLOR_PATTERN
, color
.pattern
);
1101 for (e
= MSTYLE_BORDER_TOP
; e
<= MSTYLE_BORDER_DIAGONAL
; e
++) {
1102 GnmBorder
const *ba
, *bb
;
1103 if (!elem_is_set (a
, e
))
1105 ba
= a
->borders
[e
- MSTYLE_BORDER_TOP
];
1106 bb
= b
->borders
[e
- MSTYLE_BORDER_TOP
];
1108 continue; /* Handles both being NULL */
1109 CMP_TRY_NUMBER_RAW(!!ba
, !!bb
);
1110 CMP_TRY_NUMBER_RAW(ba
->line_type
, bb
->line_type
);
1111 CMP_TRY_NUMBER_RAW(ba
->color
->go_color
, bb
->color
->go_color
);
1112 CMP_TRY_NUMBER_RAW(ba
->begin_margin
, bb
->begin_margin
);
1113 CMP_TRY_NUMBER_RAW(ba
->end_margin
, bb
->end_margin
);
1114 CMP_TRY_NUMBER_RAW(ba
->width
, bb
->width
);
1116 CMP_TRY_NUMBER (MSTYLE_PATTERN
, pattern
);
1117 if (elem_is_set (a
, MSTYLE_FONT_NAME
)) {
1118 /* Plain strcmp, not utf-8. We need to see diffs. */
1119 int tmp
= strcmp (a
->font_detail
.name
->str
,
1120 b
->font_detail
.name
->str
);
1124 CMP_TRY_NUMBER (MSTYLE_FONT_BOLD
, font_detail
.bold
);
1125 CMP_TRY_NUMBER (MSTYLE_FONT_ITALIC
, font_detail
.italic
);
1126 CMP_TRY_NUMBER (MSTYLE_FONT_UNDERLINE
, font_detail
.underline
);
1127 CMP_TRY_NUMBER (MSTYLE_FONT_STRIKETHROUGH
, font_detail
.strikethrough
);
1128 CMP_TRY_NUMBER (MSTYLE_FONT_SCRIPT
, font_detail
.script
);
1129 CMP_TRY_NUMBER (MSTYLE_FONT_SIZE
, font_detail
.size
);
1130 if (elem_is_set (a
, MSTYLE_FORMAT
)) {
1131 /* Plain strcmp, not utf-8. We need to see diffs. */
1132 int tmp
= strcmp (go_format_as_XL (a
->format
),
1133 go_format_as_XL (b
->format
));
1137 CMP_TRY_NUMBER (MSTYLE_ALIGN_H
, h_align
);
1138 CMP_TRY_NUMBER (MSTYLE_ALIGN_V
, v_align
);
1139 CMP_TRY_NUMBER (MSTYLE_INDENT
, indent
);
1140 CMP_TRY_NUMBER (MSTYLE_ROTATION
, rotation
);
1141 CMP_TRY_NUMBER (MSTYLE_TEXT_DIR
, text_dir
);
1142 CMP_TRY_NUMBER (MSTYLE_WRAP_TEXT
, wrap_text
);
1143 CMP_TRY_NUMBER (MSTYLE_SHRINK_TO_FIT
, shrink_to_fit
);
1144 CMP_TRY_NUMBER (MSTYLE_CONTENTS_LOCKED
, contents_locked
);
1145 CMP_TRY_NUMBER (MSTYLE_CONTENTS_HIDDEN
, contents_hidden
);
1146 /* FIXME: validation */
1148 /* FIXME: input_msg */
1149 /* FIXME: conditions */
1150 /* FIXME: cond_styles */
1152 /* Last resort: pointer comparison. */
1153 return a
< b
? -1 : +1;
1156 #undef CMP_TRY_NUMBER
1157 #undef CMP_TRY_COLOR
1161 * gnm_style_equal_header :
1164 * @top: is this a header vertically or horizontally
1166 * Check to see if @a is different enough from @b to make us think that @a is
1170 gnm_style_equal_header (GnmStyle
const *a
, GnmStyle
const *b
, gboolean top
)
1172 int i
= top
? MSTYLE_BORDER_BOTTOM
: MSTYLE_BORDER_RIGHT
;
1174 if (!elem_is_eq (a
, b
, i
))
1176 for (i
= MSTYLE_COLOR_BACK
; i
<= MSTYLE_COLOR_PATTERN
; i
++)
1177 if (!elem_is_eq (a
, b
, i
))
1179 for (i
= MSTYLE_FONT_COLOR
; i
<= MSTYLE_SHRINK_TO_FIT
; i
++)
1180 if (!elem_is_eq (a
, b
, i
))
1187 gnm_style_is_element_set (GnmStyle
const *style
, GnmStyleElement elem
)
1189 g_return_val_if_fail (style
!= NULL
, FALSE
);
1190 g_return_val_if_fail (MSTYLE_COLOR_BACK
<= elem
&& elem
< MSTYLE_ELEMENT_MAX
, FALSE
);
1191 return elem_is_set (style
, elem
);
1195 * gnm_style_is_complete :
1198 * Returns TRUE if all elements are set.
1201 gnm_style_is_complete (GnmStyle
const *style
)
1203 g_return_val_if_fail (style
!= NULL
, FALSE
);
1205 return style
->set
== ((1u << MSTYLE_ELEMENT_MAX
) - 1);
1209 gnm_style_unset_element (GnmStyle
*style
, GnmStyleElement elem
)
1211 g_return_if_fail (style
!= NULL
);
1212 g_return_if_fail (MSTYLE_COLOR_BACK
<= elem
&& elem
< MSTYLE_ELEMENT_MAX
);
1214 if (elem_is_set (style
, elem
)) {
1215 elem_clear_contents (style
, elem
);
1216 elem_unset (style
, elem
);
1223 * @overlay: #GnmStyle
1225 * Applies all active elements of @overlay onto @base.
1228 gnm_style_merge (GnmStyle
*base
, GnmStyle
const *overlay
)
1231 if (base
== overlay
)
1233 for (i
= 0; i
< MSTYLE_ELEMENT_MAX
; i
++)
1234 if (elem_is_set (overlay
, i
)) {
1235 elem_clear_contents (base
, i
);
1236 elem_assign_contents (base
, overlay
, i
);
1237 elem_changed (base
, i
);
1242 * gnm_style_merge_element:
1243 * @dst: Destination style
1244 * @src: Source style
1245 * @elem: Element to replace
1247 * This function replaces element @elem in style @dst with element @elem
1248 * in style @src. (If element @elem was already set in style @dst then
1249 * the element will first be unset)
1252 gnm_style_merge_element (GnmStyle
*dst
, GnmStyle
const *src
, GnmStyleElement elem
)
1254 g_return_if_fail (src
!= NULL
);
1255 g_return_if_fail (dst
!= NULL
);
1256 g_return_if_fail (src
!= dst
);
1258 if (elem_is_set (src
, elem
)) {
1259 elem_clear_contents (dst
, elem
);
1260 elem_assign_contents (dst
, src
, elem
);
1261 elem_set (dst
, elem
);
1262 elem_changed (dst
, elem
);
1267 gnm_style_set_font_color (GnmStyle
*style
, GnmColor
*col
)
1269 g_return_if_fail (style
!= NULL
);
1270 g_return_if_fail (col
!= NULL
);
1272 elem_changed (style
, MSTYLE_FONT_COLOR
);
1273 if (elem_is_set (style
, MSTYLE_FONT_COLOR
))
1274 style_color_unref (style
->color
.font
);
1276 elem_set (style
, MSTYLE_FONT_COLOR
);
1277 elem_changed (style
, MSTYLE_FONT_COLOR
);
1278 style
->color
.font
= col
;
1279 gnm_style_clear_pango (style
);
1283 * gnm_style_set_back_color :
1287 * Assigns @col as the background of @style.
1289 * NOTE : the background colour is only visibile if
1290 * GnmStyle::pattern > 0
1293 gnm_style_set_back_color (GnmStyle
*style
, GnmColor
*col
)
1295 g_return_if_fail (style
!= NULL
);
1296 g_return_if_fail (col
!= NULL
);
1298 elem_changed (style
, MSTYLE_COLOR_BACK
);
1299 if (elem_is_set (style
, MSTYLE_COLOR_BACK
))
1300 style_color_unref (style
->color
.back
);
1302 elem_set (style
, MSTYLE_COLOR_BACK
);
1303 style
->color
.back
= col
;
1304 gnm_style_clear_pango (style
);
1307 gnm_style_set_pattern_color (GnmStyle
*style
, GnmColor
*col
)
1309 g_return_if_fail (style
!= NULL
);
1310 g_return_if_fail (col
!= NULL
);
1312 elem_changed (style
, MSTYLE_COLOR_PATTERN
);
1313 if (elem_is_set (style
, MSTYLE_COLOR_PATTERN
))
1314 style_color_unref (style
->color
.pattern
);
1316 elem_set (style
, MSTYLE_COLOR_PATTERN
);
1317 style
->color
.pattern
= col
;
1318 gnm_style_clear_pango (style
);
1322 gnm_style_get_font_color (GnmStyle
const *style
)
1324 g_return_val_if_fail (style
!= NULL
, NULL
);
1325 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_COLOR
), NULL
);
1326 return style
->color
.font
;
1330 gnm_style_get_back_color (GnmStyle
const *style
)
1332 g_return_val_if_fail (style
!= NULL
, NULL
);
1333 g_return_val_if_fail (elem_is_set (style
, MSTYLE_COLOR_BACK
), NULL
);
1334 return style
->color
.back
;
1338 gnm_style_get_pattern_color (GnmStyle
const *style
)
1340 g_return_val_if_fail (style
!= NULL
, NULL
);
1341 g_return_val_if_fail (elem_is_set (style
, MSTYLE_COLOR_PATTERN
), NULL
);
1342 return style
->color
.pattern
;
1346 gnm_style_set_border (GnmStyle
*style
, GnmStyleElement elem
,
1349 g_return_if_fail (style
!= NULL
);
1351 /* NOTE : It is legal for border to be NULL */
1353 case MSTYLE_ANY_BORDER
:
1354 elem_changed (style
, elem
);
1355 elem_set (style
, elem
);
1356 elem
-= MSTYLE_BORDER_TOP
;
1357 if (style
->borders
[elem
])
1358 gnm_style_border_unref (style
->borders
[elem
]);
1359 style
->borders
[elem
] = border
;
1362 g_warning ("Not a border element");
1368 gnm_style_get_border (GnmStyle
const *style
, GnmStyleElement elem
)
1370 g_return_val_if_fail (style
!= NULL
, NULL
);
1373 case MSTYLE_ANY_BORDER
:
1374 return style
->borders
[elem
- MSTYLE_BORDER_TOP
];
1377 g_warning ("Not a border element");
1383 gnm_style_set_pattern (GnmStyle
*style
, int pattern
)
1385 g_return_if_fail (style
!= NULL
);
1386 g_return_if_fail (pattern
>= 0);
1387 g_return_if_fail (pattern
< GNM_PATTERNS_MAX
);
1389 elem_changed (style
, MSTYLE_PATTERN
);
1390 elem_set (style
, MSTYLE_PATTERN
);
1391 style
->pattern
= pattern
;
1395 gnm_style_get_pattern (GnmStyle
const *style
)
1397 g_return_val_if_fail (style
!= NULL
, 0);
1398 g_return_val_if_fail (elem_is_set (style
, MSTYLE_PATTERN
), 0);
1400 return style
->pattern
;
1404 * gnm_style_get_font:
1406 * @context: #PangoContext
1408 * Returns: (transfer none):
1411 gnm_style_get_font (GnmStyle
const *style
, PangoContext
*context
)
1413 g_return_val_if_fail (style
!= NULL
, NULL
);
1415 if (!style
->font
|| style
->font_context
!= context
) {
1417 gboolean bold
, italic
;
1420 gnm_style_clear_font ((GnmStyle
*)style
);
1422 if (elem_is_set (style
, MSTYLE_FONT_NAME
))
1423 name
= gnm_style_get_font_name (style
);
1425 name
= DEFAULT_FONT
;
1427 if (elem_is_set (style
, MSTYLE_FONT_BOLD
))
1428 bold
= gnm_style_get_font_bold (style
);
1432 if (elem_is_set (style
, MSTYLE_FONT_ITALIC
))
1433 italic
= gnm_style_get_font_italic (style
);
1437 if (elem_is_set (style
, MSTYLE_FONT_SIZE
))
1438 size
= gnm_style_get_font_size (style
);
1440 size
= DEFAULT_SIZE
;
1442 ((GnmStyle
*)style
)->font
=
1443 gnm_font_new (context
, name
, size
, bold
, italic
);
1444 ((GnmStyle
*)style
)->font_context
= g_object_ref (context
);
1451 gnm_style_set_font_name (GnmStyle
*style
, char const *name
)
1453 g_return_if_fail (name
!= NULL
);
1454 g_return_if_fail (style
!= NULL
);
1456 elem_changed (style
, MSTYLE_FONT_NAME
);
1457 if (elem_is_set (style
, MSTYLE_FONT_NAME
))
1458 go_string_unref (style
->font_detail
.name
);
1460 elem_set (style
, MSTYLE_FONT_NAME
);
1461 style
->font_detail
.name
= go_string_new (name
);
1462 gnm_style_clear_font (style
);
1463 gnm_style_clear_pango (style
);
1467 gnm_style_get_font_name (GnmStyle
const *style
)
1469 g_return_val_if_fail (style
!= NULL
, NULL
);
1470 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_NAME
), NULL
);
1472 return style
->font_detail
.name
->str
;
1476 gnm_style_set_font_bold (GnmStyle
*style
, gboolean bold
)
1478 g_return_if_fail (style
!= NULL
);
1480 elem_changed (style
, MSTYLE_FONT_BOLD
);
1481 elem_set (style
, MSTYLE_FONT_BOLD
);
1482 style
->font_detail
.bold
= !!bold
;
1483 gnm_style_clear_font (style
);
1484 gnm_style_clear_pango (style
);
1488 gnm_style_get_font_bold (GnmStyle
const *style
)
1490 g_return_val_if_fail (style
!= NULL
, FALSE
);
1491 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_BOLD
), FALSE
);
1493 return style
->font_detail
.bold
;
1497 gnm_style_set_font_italic (GnmStyle
*style
, gboolean italic
)
1499 g_return_if_fail (style
!= NULL
);
1501 elem_changed (style
, MSTYLE_FONT_ITALIC
);
1502 elem_set (style
, MSTYLE_FONT_ITALIC
);
1503 style
->font_detail
.italic
= !!italic
;
1504 gnm_style_clear_font (style
);
1505 gnm_style_clear_pango (style
);
1509 gnm_style_get_font_italic (GnmStyle
const *style
)
1511 g_return_val_if_fail (style
!= NULL
, FALSE
);
1512 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_ITALIC
), FALSE
);
1514 return style
->font_detail
.italic
;
1518 gnm_style_set_font_uline (GnmStyle
*style
, GnmUnderline
const underline
)
1520 g_return_if_fail (style
!= NULL
);
1521 g_return_if_fail (underline
>= UNDERLINE_NONE
&& underline
<= UNDERLINE_DOUBLE_LOW
);
1523 elem_changed (style
, MSTYLE_FONT_UNDERLINE
);
1524 elem_set (style
, MSTYLE_FONT_UNDERLINE
);
1525 style
->font_detail
.underline
= underline
;
1526 gnm_style_clear_pango (style
);
1530 gnm_style_get_font_uline (GnmStyle
const *style
)
1532 g_return_val_if_fail (style
!= NULL
, UNDERLINE_NONE
);
1533 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_UNDERLINE
), UNDERLINE_NONE
);
1535 return style
->font_detail
.underline
;
1539 gnm_style_set_font_strike (GnmStyle
*style
, gboolean strikethrough
)
1541 g_return_if_fail (style
!= NULL
);
1543 elem_changed (style
, MSTYLE_FONT_STRIKETHROUGH
);
1544 elem_set (style
, MSTYLE_FONT_STRIKETHROUGH
);
1545 style
->font_detail
.strikethrough
= !!strikethrough
;
1546 gnm_style_clear_pango (style
);
1550 gnm_style_get_font_strike (GnmStyle
const *style
)
1552 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_STRIKETHROUGH
), FALSE
);
1554 return style
->font_detail
.strikethrough
;
1558 gnm_style_set_font_script (GnmStyle
*style
, GOFontScript script
)
1560 g_return_if_fail (style
!= NULL
);
1561 elem_changed (style
, MSTYLE_FONT_SCRIPT
);
1562 elem_set (style
, MSTYLE_FONT_SCRIPT
);
1563 style
->font_detail
.script
= script
;
1564 gnm_style_clear_pango (style
);
1568 gnm_style_get_font_script (GnmStyle
const *style
)
1570 g_return_val_if_fail (style
!= NULL
, GO_FONT_SCRIPT_STANDARD
);
1571 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_SCRIPT
), GO_FONT_SCRIPT_STANDARD
);
1573 return style
->font_detail
.script
;
1577 gnm_style_set_font_size (GnmStyle
*style
, double size
)
1579 g_return_if_fail (style
!= NULL
);
1580 g_return_if_fail (size
>= 1.);
1581 elem_changed (style
, MSTYLE_FONT_SIZE
);
1582 elem_set (style
, MSTYLE_FONT_SIZE
);
1583 style
->font_detail
.size
= size
;
1584 gnm_style_clear_font (style
);
1585 gnm_style_clear_pango (style
);
1589 gnm_style_get_font_size (GnmStyle
const *style
)
1591 g_return_val_if_fail (style
!= NULL
, 12.0);
1592 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_SIZE
), 12.0);
1594 return style
->font_detail
.size
;
1598 gnm_style_set_format (GnmStyle
*style
, GOFormat
const *format
)
1600 g_return_if_fail (style
!= NULL
);
1601 g_return_if_fail (format
!= NULL
);
1603 elem_changed (style
, MSTYLE_FORMAT
);
1604 go_format_ref (format
);
1605 elem_clear_contents (style
, MSTYLE_FORMAT
);
1606 elem_set (style
, MSTYLE_FORMAT
);
1607 style
->format
= format
;
1611 * gnm_style_set_format_text:
1613 * @style: mstyle to change.
1614 * @format: An *untranslated* format string.
1617 gnm_style_set_format_text (GnmStyle
*style
, char const *format
)
1621 g_return_if_fail (style
!= NULL
);
1622 g_return_if_fail (format
!= NULL
);
1624 sf
= go_format_new_from_XL (format
);
1625 gnm_style_set_format (style
, sf
);
1626 go_format_unref (sf
);
1630 gnm_style_get_format (GnmStyle
const *style
)
1632 g_return_val_if_fail (style
!= NULL
, NULL
);
1633 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FORMAT
), NULL
);
1635 return style
->format
;
1639 gnm_style_set_align_h (GnmStyle
*style
, GnmHAlign a
)
1641 g_return_if_fail (style
!= NULL
);
1643 elem_changed (style
, MSTYLE_ALIGN_H
);
1644 elem_set (style
, MSTYLE_ALIGN_H
);
1649 gnm_style_get_align_h (GnmStyle
const *style
)
1651 g_return_val_if_fail (style
!= NULL
, GNM_HALIGN_LEFT
);
1652 g_return_val_if_fail (elem_is_set (style
, MSTYLE_ALIGN_H
), GNM_HALIGN_LEFT
);
1654 return style
->h_align
;
1658 gnm_style_set_align_v (GnmStyle
*style
, GnmVAlign a
)
1660 g_return_if_fail (style
!= NULL
);
1662 elem_changed (style
, MSTYLE_ALIGN_V
);
1663 elem_set (style
, MSTYLE_ALIGN_V
);
1668 gnm_style_get_align_v (GnmStyle
const *style
)
1670 g_return_val_if_fail (style
!= NULL
, GNM_VALIGN_TOP
);
1671 g_return_val_if_fail (elem_is_set (style
, MSTYLE_ALIGN_V
), GNM_VALIGN_TOP
);
1673 return style
->v_align
;
1677 gnm_style_set_indent (GnmStyle
*style
, int i
)
1679 g_return_if_fail (style
!= NULL
);
1681 elem_changed (style
, MSTYLE_INDENT
);
1682 elem_set (style
, MSTYLE_INDENT
);
1687 gnm_style_get_indent (GnmStyle
const *style
)
1689 g_return_val_if_fail (style
!= NULL
, 0);
1690 g_return_val_if_fail (elem_is_set (style
, MSTYLE_INDENT
), 0);
1692 return style
->indent
;
1696 gnm_style_set_rotation (GnmStyle
*style
, int rot_deg
)
1698 g_return_if_fail (style
!= NULL
);
1700 elem_changed (style
, MSTYLE_ROTATION
);
1701 elem_set (style
, MSTYLE_ROTATION
);
1702 style
->rotation
= rot_deg
;
1706 gnm_style_get_rotation (GnmStyle
const *style
)
1708 g_return_val_if_fail (style
!= NULL
, 0);
1709 g_return_val_if_fail (elem_is_set (style
, MSTYLE_ROTATION
), 0);
1711 return style
->rotation
;
1715 gnm_style_set_text_dir (GnmStyle
*style
, GnmTextDir text_dir
)
1717 g_return_if_fail (style
!= NULL
);
1719 elem_changed (style
, MSTYLE_TEXT_DIR
);
1720 elem_set (style
, MSTYLE_TEXT_DIR
);
1721 style
->text_dir
= text_dir
;
1725 gnm_style_get_text_dir (GnmStyle
const *style
)
1727 g_return_val_if_fail (style
!= NULL
, GNM_TEXT_DIR_CONTEXT
);
1728 g_return_val_if_fail (elem_is_set (style
, MSTYLE_TEXT_DIR
), GNM_TEXT_DIR_CONTEXT
);
1730 return style
->text_dir
;
1734 gnm_style_set_wrap_text (GnmStyle
*style
, gboolean f
)
1736 g_return_if_fail (style
!= NULL
);
1738 elem_changed (style
, MSTYLE_WRAP_TEXT
);
1739 elem_set (style
, MSTYLE_WRAP_TEXT
);
1740 style
->wrap_text
= !!f
;
1744 gnm_style_get_wrap_text (GnmStyle
const *style
)
1746 g_return_val_if_fail (elem_is_set (style
, MSTYLE_WRAP_TEXT
), FALSE
);
1748 return style
->wrap_text
;
1752 * Same as gnm_style_get_wrap_text except that if either halign or valign
1753 * is _JUSTIFY, the result will be TRUE.
1756 gnm_style_get_effective_wrap_text (GnmStyle
const *style
)
1758 g_return_val_if_fail (style
!= NULL
, FALSE
);
1759 g_return_val_if_fail (elem_is_set (style
, MSTYLE_WRAP_TEXT
), FALSE
);
1760 g_return_val_if_fail (elem_is_set (style
, MSTYLE_ALIGN_V
), FALSE
);
1761 g_return_val_if_fail (elem_is_set (style
, MSTYLE_ALIGN_H
), FALSE
);
1763 /* Note: GNM_HALIGN_GENERAL never expands to GNM_HALIGN_JUSTIFY. */
1764 return (style
->wrap_text
||
1765 style
->v_align
== GNM_VALIGN_JUSTIFY
||
1766 style
->v_align
== GNM_VALIGN_DISTRIBUTED
||
1767 style
->h_align
== GNM_HALIGN_JUSTIFY
);
1771 gnm_style_set_shrink_to_fit (GnmStyle
*style
, gboolean f
)
1773 g_return_if_fail (style
!= NULL
);
1775 elem_changed (style
, MSTYLE_SHRINK_TO_FIT
);
1776 elem_set (style
, MSTYLE_SHRINK_TO_FIT
);
1777 style
->shrink_to_fit
= !!f
;
1781 gnm_style_get_shrink_to_fit (GnmStyle
const *style
)
1783 g_return_val_if_fail (style
!= NULL
, FALSE
);
1784 g_return_val_if_fail (elem_is_set (style
, MSTYLE_SHRINK_TO_FIT
), FALSE
);
1786 return style
->shrink_to_fit
;
1790 gnm_style_set_contents_locked (GnmStyle
*style
, gboolean f
)
1792 g_return_if_fail (style
!= NULL
);
1794 elem_changed (style
, MSTYLE_CONTENTS_LOCKED
);
1795 elem_set (style
, MSTYLE_CONTENTS_LOCKED
);
1796 style
->contents_locked
= !!f
;
1800 gnm_style_get_contents_locked (GnmStyle
const *style
)
1802 g_return_val_if_fail (style
!= NULL
, FALSE
);
1803 g_return_val_if_fail (elem_is_set (style
, MSTYLE_CONTENTS_LOCKED
), FALSE
);
1805 return style
->contents_locked
;
1809 gnm_style_set_contents_hidden (GnmStyle
*style
, gboolean f
)
1811 g_return_if_fail (style
!= NULL
);
1813 elem_changed (style
, MSTYLE_CONTENTS_HIDDEN
);
1814 elem_set (style
, MSTYLE_CONTENTS_HIDDEN
);
1815 style
->contents_hidden
= !!f
;
1819 gnm_style_get_contents_hidden (GnmStyle
const *style
)
1821 g_return_val_if_fail (style
!= NULL
, FALSE
);
1822 g_return_val_if_fail (elem_is_set (style
, MSTYLE_CONTENTS_HIDDEN
), FALSE
);
1824 return style
->contents_hidden
;
1828 * gnm_style_set_validation:
1830 * @v: (transfer full): #GnmValidation
1833 gnm_style_set_validation (GnmStyle
*style
, GnmValidation
*v
)
1835 g_return_if_fail (style
!= NULL
);
1837 elem_clear_contents (style
, MSTYLE_VALIDATION
);
1838 elem_changed (style
, MSTYLE_VALIDATION
);
1839 elem_set (style
, MSTYLE_VALIDATION
);
1840 style
->validation
= v
;
1844 * gnm_style_get_validation:
1847 * Returns: (transfer none):
1849 GnmValidation
const *
1850 gnm_style_get_validation (GnmStyle
const *style
)
1852 g_return_val_if_fail (style
!= NULL
, NULL
);
1853 g_return_val_if_fail (elem_is_set (style
, MSTYLE_VALIDATION
), NULL
);
1855 return style
->validation
;
1859 * gnm_style_set_hlink:
1861 * @lnk: (transfer full): #GnmHLink
1863 * This sets a link for @style.
1866 gnm_style_set_hlink (GnmStyle
*style
, GnmHLink
*lnk
)
1868 g_return_if_fail (style
!= NULL
);
1870 elem_clear_contents (style
, MSTYLE_HLINK
);
1871 elem_changed (style
, MSTYLE_HLINK
);
1872 elem_set (style
, MSTYLE_HLINK
);
1877 * gnm_style_get_hlink:
1880 * Returns: (transfer none): the associated #GnmHLink.
1883 gnm_style_get_hlink (GnmStyle
const *style
)
1885 g_return_val_if_fail (style
!= NULL
, NULL
);
1886 g_return_val_if_fail (elem_is_set (style
, MSTYLE_HLINK
), NULL
);
1888 return style
->hlink
;
1892 * gnm_style_set_input_msg:
1894 * @msg: (transfer full): #GnmInputMsg
1896 * This sets an input message for @style.
1899 gnm_style_set_input_msg (GnmStyle
*style
, GnmInputMsg
*msg
)
1901 g_return_if_fail (style
!= NULL
);
1903 elem_clear_contents (style
, MSTYLE_INPUT_MSG
);
1904 elem_changed (style
, MSTYLE_INPUT_MSG
);
1905 elem_set (style
, MSTYLE_INPUT_MSG
);
1906 style
->input_msg
= msg
;
1910 * gnm_style_get_input_msg:
1913 * Returns: (transfer none): the currently set input message assuming
1914 * that the style has such.
1917 gnm_style_get_input_msg (GnmStyle
const *style
)
1919 g_return_val_if_fail (style
!= NULL
, NULL
);
1920 g_return_val_if_fail (elem_is_set (style
, MSTYLE_INPUT_MSG
), NULL
);
1922 return style
->input_msg
;
1926 * gnm_style_set_conditions:
1928 * @sc: (transfer full): #GnmStyleConditions
1930 * This sets conditional style for @style.
1933 gnm_style_set_conditions (GnmStyle
*style
, GnmStyleConditions
*sc
)
1935 g_return_if_fail (style
!= NULL
);
1937 elem_clear_contents (style
, MSTYLE_CONDITIONS
);
1938 elem_changed (style
, MSTYLE_CONDITIONS
);
1939 elem_set (style
, MSTYLE_CONDITIONS
);
1940 style
->conditions
= sc
;
1944 * gnm_style_get_conditions:
1947 * Returns: (transfer none): the currently set conditional style assuming
1948 * that the style has such.
1950 GnmStyleConditions
*
1951 gnm_style_get_conditions (GnmStyle
const *style
)
1953 g_return_val_if_fail (style
!= NULL
, NULL
);
1954 g_return_val_if_fail (elem_is_set (style
, MSTYLE_CONDITIONS
), NULL
);
1955 return style
->conditions
;
1959 debug_style_deps (void)
1961 static int debug
= -1;
1963 debug
= gnm_debug_flag ("style-deps");
1968 * Just a simple version for now. We can also ignore most function
1969 * calls[1] and self-references[2].
1971 * [1] Excluding volatile (TODAY, ...) and those that can create references
1972 * outside the arguments (INDIRECT).
1974 * [2] References that print like A1 when used in A1.
1977 cond_expr_harmless (GnmExpr
const *expr
)
1979 GnmValue
const *v
= gnm_expr_get_constant (expr
);
1980 if (v
&& !VALUE_IS_CELLRANGE (v
))
1988 gnm_style_link_dependents (GnmStyle
*style
, GnmRange
const *r
)
1990 GnmStyleConditions
*sc
;
1993 g_return_if_fail (style
!= NULL
);
1994 g_return_if_fail (r
!= NULL
);
1996 sheet
= style
->linked_sheet
;
1999 * Conditional formatting.
2001 * We need to trigger a reformatting of the cell if a cell referenced
2002 * by the condition changes.
2004 sc
= elem_is_set (style
, MSTYLE_CONDITIONS
)
2005 ? gnm_style_get_conditions (style
)
2008 GPtrArray
const *conds
= gnm_style_conditions_details (sc
);
2010 if (debug_style_deps ())
2011 g_printerr ("Linking %s for %p\n",
2012 range_as_string (r
), style
);
2013 for (ui
= 0; conds
&& ui
< conds
->len
; ui
++) {
2014 GnmStyleCond
const *c
= g_ptr_array_index (conds
, ui
);
2017 for (ei
= 0; ei
< 2; ei
++) {
2018 GnmExprTop
const *texpr
=
2019 gnm_style_cond_get_expr (c
, ei
);
2021 cond_expr_harmless (texpr
->expr
))
2024 style
->deps
= g_ptr_array_new ();
2025 gnm_dep_style_dependency
2026 (sheet
, texpr
, r
, style
->deps
);
2034 * We can probably ignore those. If a dependent cell changes such
2035 * that a validation condition is no longer satisfied, it is
2036 * grandfathered in as valid.
2039 /* The style owns the deps. */
2043 gnm_style_unlink_dependents (GnmStyle
*style
, GnmRange
const *r
)
2047 g_return_if_fail (style
!= NULL
);
2048 g_return_if_fail (r
!= NULL
);
2053 for (ui
= k
= 0; ui
< style
->deps
->len
; ui
++) {
2054 GnmDependent
*dep
= g_ptr_array_index (style
->deps
, ui
);
2055 GnmCellPos
const *pos
= dependent_pos (dep
);
2057 if (range_contains (r
, pos
->col
, pos
->row
)) {
2058 if (debug_style_deps ())
2059 g_printerr ("Unlinking %s for %p\n",
2060 cellpos_as_string (pos
), style
);
2061 dependent_set_expr (dep
, NULL
);
2064 g_ptr_array_index (style
->deps
, k
) = dep
;
2069 g_ptr_array_set_size (style
->deps
, k
);
2074 * gnm_style_visible_in_blank:
2075 * @style: style to query
2077 * Returns: %TRUE if the style is visible, i.e., not transparent. Specifically
2078 * that means if it has a background or a visible border.
2081 gnm_style_visible_in_blank (GnmStyle
const *style
)
2085 g_return_val_if_fail (style
!= NULL
, FALSE
);
2087 if (elem_is_set (style
, MSTYLE_PATTERN
) &&
2088 gnm_style_get_pattern (style
) > 0)
2091 for (i
= MSTYLE_BORDER_TOP
; i
<= MSTYLE_BORDER_DIAGONAL
; ++i
)
2092 if (elem_is_set (style
, i
) &&
2093 gnm_style_border_visible_in_blank (gnm_style_get_border (style
, i
)))
2100 add_attr (PangoAttrList
*attrs
, PangoAttribute
*attr
)
2102 attr
->start_index
= 0;
2103 attr
->end_index
= G_MAXINT
;
2104 pango_attr_list_insert (attrs
, attr
);
2108 * gnm_style_get_pango_attrs :
2112 gnm_style_get_pango_attrs (GnmStyle
const *style
,
2113 PangoContext
*context
,
2118 GnmFont
*font
= gnm_style_get_font (style
, context
);
2120 if (style
->pango_attrs
) {
2121 if (zoom
== style
->pango_attrs_zoom
) {
2122 pango_attr_list_ref (style
->pango_attrs
);
2123 return style
->pango_attrs
;
2125 pango_attr_list_unref (((GnmStyle
*)style
)->pango_attrs
);
2128 ((GnmStyle
*)style
)->pango_attrs
= l
= pango_attr_list_new ();
2129 ((GnmStyle
*)style
)->pango_attrs_zoom
= zoom
;
2130 ((GnmStyle
*)style
)->pango_attrs_height
= -1;
2132 /* Foreground colour. */
2133 /* See http://bugzilla.gnome.org/show_bug.cgi?id=105322 */
2135 GnmColor
const *fore
= style
->color
.font
;
2136 add_attr (l
, go_color_to_pango (fore
->go_color
, TRUE
));
2139 /* Handle underlining. */
2140 ul
= gnm_style_get_font_uline (style
);
2141 if (ul
!= UNDERLINE_NONE
)
2143 pango_attr_underline_new (gnm_translate_underline_to_pango (ul
)));
2145 /* Handle strikethrough. */
2146 if (gnm_style_get_font_strike (style
))
2147 add_attr (l
, pango_attr_strikethrough_new (TRUE
));
2149 /* Handle script. */
2150 switch (gnm_style_get_font_script (style
)) {
2152 case GO_FONT_SCRIPT_STANDARD
:
2154 case GO_FONT_SCRIPT_SUB
:
2155 add_attr (l
, go_pango_attr_subscript_new (TRUE
));
2157 case GO_FONT_SCRIPT_SUPER
:
2158 add_attr (l
, go_pango_attr_superscript_new (TRUE
));
2162 add_attr (l
, pango_attr_font_desc_new (font
->go
.font
->desc
));
2165 add_attr (l
, pango_attr_scale_new (zoom
));
2167 pango_attr_list_ref (l
);
2172 gnm_style_generate_attrs_full (GnmStyle
const *style
)
2174 GnmColor
const *fore
= style
->color
.font
;
2175 PangoAttrList
*l
= pango_attr_list_new ();
2177 add_attr (l
, pango_attr_family_new (gnm_style_get_font_name (style
)));
2178 add_attr (l
, pango_attr_size_new (gnm_style_get_font_size (style
) * PANGO_SCALE
));
2179 add_attr (l
, pango_attr_style_new (gnm_style_get_font_italic (style
)
2180 ? PANGO_STYLE_ITALIC
: PANGO_STYLE_NORMAL
));
2181 add_attr (l
, pango_attr_weight_new (gnm_style_get_font_bold (style
)
2182 ? PANGO_WEIGHT_BOLD
: PANGO_WEIGHT_NORMAL
));
2183 add_attr (l
, go_color_to_pango (fore
->go_color
, TRUE
));
2184 add_attr (l
, pango_attr_strikethrough_new
2185 (gnm_style_get_font_strike (style
)));
2186 add_attr (l
, pango_attr_underline_new
2187 (gnm_translate_underline_to_pango
2188 (gnm_style_get_font_uline (style
))));
2193 gnm_style_get_pango_height (GnmStyle
const *style
,
2194 PangoContext
*context
,
2197 PangoAttrList
*attrs
= gnm_style_get_pango_attrs (style
, context
, zoom
);
2199 if (style
->pango_attrs_height
== -1) {
2201 PangoLayout
*layout
= pango_layout_new (context
);
2202 GOFormat
const *fmt
;
2203 gboolean requires_translation
= FALSE
;
2205 fmt
= gnm_style_get_format (style
);
2206 if (!go_format_is_general (fmt
)) {
2207 GOFormatDetails details
;
2208 go_format_get_details (fmt
, &details
, NULL
);
2209 if (details
.family
== GO_FORMAT_SCIENTIFIC
&&
2210 details
.use_markup
) {
2212 = go_pango_attr_superscript_new (TRUE
);
2213 /* We want to superscript the "-01" in the */
2214 /* string "+1.23456789E-01" */
2215 a
->start_index
= 12;
2217 pango_attr_list_insert (attrs
, a
);
2218 requires_translation
= TRUE
;
2221 pango_layout_set_attributes (layout
, attrs
);
2222 pango_layout_set_text (layout
, "+1.23456789E-01", -1);
2223 if (requires_translation
)
2224 go_pango_translate_layout (layout
);
2225 pango_layout_get_pixel_size (layout
, NULL
, &h
);
2226 g_object_unref (layout
);
2227 ((GnmStyle
*)style
)->pango_attrs_height
= h
;
2230 pango_attr_list_unref (attrs
);
2231 return style
->pango_attrs_height
;
2236 gnm_style_set_from_pango_attribute (GnmStyle
*style
, PangoAttribute
const *attr
)
2238 switch (attr
->klass
->type
) {
2239 case PANGO_ATTR_FAMILY
:
2240 gnm_style_set_font_name (style
, ((PangoAttrString
*)attr
)->value
);
2242 case PANGO_ATTR_SIZE
:
2243 gnm_style_set_font_size (style
,
2244 ((PangoAttrInt
*)attr
)->value
/ (double)PANGO_SCALE
);
2246 case PANGO_ATTR_STYLE
:
2247 gnm_style_set_font_italic (style
,
2248 ((PangoAttrInt
*)attr
)->value
== PANGO_STYLE_ITALIC
);
2250 case PANGO_ATTR_WEIGHT
:
2251 gnm_style_set_font_bold (style
,
2252 ((PangoAttrInt
*)attr
)->value
>= PANGO_WEIGHT_BOLD
);
2254 case PANGO_ATTR_FOREGROUND
:
2255 gnm_style_set_font_color (style
, gnm_color_new_pango (
2256 &((PangoAttrColor
*)attr
)->color
));
2258 case PANGO_ATTR_UNDERLINE
:
2259 gnm_style_set_font_uline
2260 (style
, gnm_translate_underline_from_pango
2261 (((PangoAttrInt
*)attr
)->value
));
2263 case PANGO_ATTR_STRIKETHROUGH
:
2264 gnm_style_set_font_strike (style
,
2265 ((PangoAttrInt
*)attr
)->value
!= 0);
2268 gboolean script_seen
= FALSE
, script_set
= FALSE
;
2269 if (attr
->klass
->type
== go_pango_attr_superscript_get_attr_type ()) {
2271 if (((GOPangoAttrSuperscript
*)attr
)->val
== 1) {
2273 gnm_style_set_font_script
2274 (style
, GO_FONT_SCRIPT_SUPER
);
2276 } else if (attr
->klass
->type
== go_pango_attr_subscript_get_attr_type ()) {
2278 if (((GOPangoAttrSubscript
*)attr
)->val
== 1) {
2280 gnm_style_set_font_script
2281 (style
, GO_FONT_SCRIPT_SUB
);
2284 if (script_seen
&& !script_set
)
2285 gnm_style_set_font_script
2286 (style
, GO_FONT_SCRIPT_STANDARD
);
2287 break; /* ignored */
2292 /* ------------------------------------------------------------------------- */
2295 gnm_style_dump_color (GnmColor
*color
, GnmStyleElement elem
)
2298 g_printerr ("\t%s: %x:%x:%x%s\n",
2299 gnm_style_element_name
[elem
],
2300 GO_COLOR_UINT_R (color
->go_color
),
2301 GO_COLOR_UINT_G (color
->go_color
),
2302 GO_COLOR_UINT_B (color
->go_color
),
2303 color
->is_auto
? " auto" : "");
2305 g_printerr ("\t%s: (NULL)\n", gnm_style_element_name
[elem
]);
2309 gnm_style_dump_border (GnmBorder
*border
, GnmStyleElement elem
)
2311 g_printerr ("\t%s: ", gnm_style_element_name
[elem
]);
2313 g_printerr ("%d\n", border
->line_type
);
2315 g_printerr ("blank\n");
2320 * @style: style to dump
2322 * This function dumps the given style's contents to stderr. This is meant
2323 * for debug purposes only and doesn't do a very good job for, for example,
2324 * conditional style settings.
2327 gnm_style_dump (GnmStyle
const *style
)
2331 g_printerr ("Style Refs %d\n", style
->ref_count
);
2332 if (elem_is_set (style
, MSTYLE_COLOR_BACK
))
2333 gnm_style_dump_color (style
->color
.back
, MSTYLE_COLOR_BACK
);
2334 if (elem_is_set (style
, MSTYLE_COLOR_PATTERN
))
2335 gnm_style_dump_color (style
->color
.pattern
, MSTYLE_COLOR_PATTERN
);
2337 for (i
= MSTYLE_BORDER_TOP
; i
<= MSTYLE_BORDER_DIAGONAL
; ++i
)
2338 if (elem_is_set (style
, i
))
2339 gnm_style_dump_border (style
->borders
[i
-MSTYLE_BORDER_TOP
], i
);
2341 if (elem_is_set (style
, MSTYLE_PATTERN
))
2342 g_printerr ("\tpattern %d\n", style
->pattern
);
2343 if (elem_is_set (style
, MSTYLE_FONT_COLOR
))
2344 gnm_style_dump_color (style
->color
.font
, MSTYLE_FONT_COLOR
);
2345 if (elem_is_set (style
, MSTYLE_FONT_NAME
))
2346 g_printerr ("\tname '%s'\n", style
->font_detail
.name
->str
);
2347 if (elem_is_set (style
, MSTYLE_FONT_BOLD
))
2348 g_printerr (style
->font_detail
.bold
? "\tbold\n" : "\tnot bold\n");
2349 if (elem_is_set (style
, MSTYLE_FONT_ITALIC
))
2350 g_printerr (style
->font_detail
.italic
? "\titalic\n" : "\tnot italic\n");
2351 if (elem_is_set (style
, MSTYLE_FONT_UNDERLINE
))
2352 switch (style
->font_detail
.underline
) {
2354 case UNDERLINE_NONE
:
2355 g_printerr ("\tno underline\n"); break;
2356 case UNDERLINE_SINGLE
:
2357 g_printerr ("\tsingle underline\n"); break;
2358 case UNDERLINE_DOUBLE
:
2359 g_printerr ("\tdouble underline\n"); break;
2361 if (elem_is_set (style
, MSTYLE_FONT_STRIKETHROUGH
))
2362 g_printerr (style
->font_detail
.strikethrough
? "\tstrikethrough\n" : "\tno strikethrough\n");
2363 if (elem_is_set (style
, MSTYLE_FONT_SCRIPT
))
2364 switch (style
->font_detail
.script
) {
2365 case GO_FONT_SCRIPT_SUB
:
2366 g_printerr ("\tsubscript\n"); break;
2368 case GO_FONT_SCRIPT_STANDARD
:
2369 g_printerr ("\tno super or sub\n"); break;
2370 case GO_FONT_SCRIPT_SUPER
:
2371 g_printerr ("\tsuperscript\n"); break;
2373 if (elem_is_set (style
, MSTYLE_FONT_SIZE
))
2374 g_printerr ("\tsize %f\n", style
->font_detail
.size
);
2375 if (elem_is_set (style
, MSTYLE_FORMAT
)) {
2376 const char *fmt
= go_format_as_XL (style
->format
);
2377 g_printerr ("\tformat '%s'\n", fmt
);
2379 if (elem_is_set (style
, MSTYLE_ALIGN_V
))
2380 g_printerr ("\tvalign %hd\n", (short)style
->v_align
);
2381 if (elem_is_set (style
, MSTYLE_ALIGN_H
))
2382 g_printerr ("\thalign %hd\n", (short)style
->h_align
);
2383 if (elem_is_set (style
, MSTYLE_INDENT
))
2384 g_printerr ("\tindent %d\n", style
->indent
);
2385 if (elem_is_set (style
, MSTYLE_ROTATION
))
2386 g_printerr ("\trotation %d\n", style
->rotation
);
2387 if (elem_is_set (style
, MSTYLE_TEXT_DIR
))
2388 g_printerr ("\ttext dir %d\n", style
->text_dir
);
2389 if (elem_is_set (style
, MSTYLE_WRAP_TEXT
))
2390 g_printerr ("\twrap text %d\n", style
->wrap_text
);
2391 if (elem_is_set (style
, MSTYLE_SHRINK_TO_FIT
))
2392 g_printerr ("\tshrink to fit %d\n", style
->shrink_to_fit
);
2393 if (elem_is_set (style
, MSTYLE_CONTENTS_LOCKED
))
2394 g_printerr ("\tlocked %d\n", style
->contents_locked
);
2395 if (elem_is_set (style
, MSTYLE_CONTENTS_HIDDEN
))
2396 g_printerr ("\thidden %d\n", style
->contents_hidden
);
2397 if (elem_is_set (style
, MSTYLE_VALIDATION
))
2398 g_printerr ("\tvalidation %p\n", (void *)style
->validation
);
2399 if (elem_is_set (style
, MSTYLE_HLINK
))
2400 g_printerr ("\thlink %p\n", (void *)style
->hlink
);
2401 if (elem_is_set (style
, MSTYLE_INPUT_MSG
))
2402 g_printerr ("\tinput msg %p\n", (void *)style
->input_msg
);
2403 if (elem_is_set (style
, MSTYLE_CONDITIONS
))
2404 g_printerr ("\tconditions %p\n", (void *)style
->conditions
);
2407 /* ------------------------------------------------------------------------- */
2410 gnm_style_init (void)
2414 go_mem_chunk_new ("style pool",
2422 cb_gnm_style_pool_leak (gpointer data
, G_GNUC_UNUSED gpointer user
)
2424 GnmStyle
*style
= data
;
2425 g_printerr ("Leaking style at %p.\n", (void *)style
);
2426 gnm_style_dump (style
);
2431 gnm_style_shutdown (void)
2434 go_mem_chunk_foreach_leak (gnm_style_pool
, cb_gnm_style_pool_leak
, NULL
);
2435 go_mem_chunk_destroy (gnm_style_pool
, FALSE
);
2436 gnm_style_pool
= NULL
;