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 "input-msg.h"
20 #include "application.h"
21 #include "parse-util.h"
26 #include "gnumeric-conf.h"
27 #include <goffice/goffice.h>
31 #ifndef USE_MSTYLE_POOL
32 #define USE_MSTYLE_POOL 1
36 /* Memory pool for GnmStyles. */
37 static GOMemChunk
*gnm_style_pool
;
38 #define CHUNK_ALLOC(T,p) ((T*)go_mem_chunk_alloc (p))
39 #define CHUNK_ALLOC0(T,p) ((T*)go_mem_chunk_alloc0 (p))
40 #define CHUNK_FREE(p,v) go_mem_chunk_free ((p), (v))
42 #define CHUNK_ALLOC(T,c) g_new (T,1)
43 #define CHUNK_ALLOC0(T,c) g_new0 (T,1)
44 #define CHUNK_FREE(p,v) g_free ((v))
47 #define UNROLLED_FOR(init_,cond_,step_,code_) \
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 if (cond_) { code_; step_; \
100 g_assert_not_reached (); \
101 }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} \
106 static char const * const
107 gnm_style_element_name
[MSTYLE_ELEMENT_MAX
] = {
114 "Border.RevDiagonal",
122 "Font.Strikethrough",
139 /* Some ref/link count debugging */
141 #define d(arg) g_printerr arg
143 #define d(arg) do { } while (0)
147 clear_conditional_merges (GnmStyle
*style
)
149 if (style
->cond_styles
) {
150 unsigned i
= style
->cond_styles
->len
;
152 gnm_style_unref (g_ptr_array_index (style
->cond_styles
, i
));
153 g_ptr_array_free (style
->cond_styles
, TRUE
);
154 style
->cond_styles
= NULL
;
158 #define MIX(H) do { \
159 H *= G_GUINT64_CONSTANT(123456789012345); \
164 gnm_style_update (GnmStyle
*style
)
169 g_return_if_fail (style
->changed
);
173 clear_conditional_merges (style
);
174 if (elem_is_set (style
, MSTYLE_CONDITIONS
) && style
->conditions
)
175 style
->cond_styles
= gnm_style_conditions_overlay (style
->conditions
, style
);
177 /* ---------------------------------------- */
179 if (elem_is_set (style
, MSTYLE_COLOR_BACK
)) {
180 if (!style
->color
.back
->is_auto
)
181 hash
^= GPOINTER_TO_UINT (style
->color
.back
);
187 if (elem_is_set (style
, MSTYLE_COLOR_PATTERN
)) {
188 if (!style
->color
.pattern
->is_auto
)
189 hash
^= GPOINTER_TO_UINT (style
->color
.pattern
);
195 if (elem_is_set (style
, MSTYLE_FONT_COLOR
)) {
196 if (!style
->color
.font
->is_auto
)
197 hash
^= GPOINTER_TO_UINT (style
->color
.font
);
203 for (i
= MSTYLE_BORDER_TOP
; i
<= MSTYLE_BORDER_DIAGONAL
; i
++) {
204 if (elem_is_set (style
, i
))
205 hash
^= GPOINTER_TO_UINT (style
->borders
[i
- MSTYLE_BORDER_TOP
]);
211 if (elem_is_set (style
, MSTYLE_PATTERN
))
212 hash
^= style
->pattern
;
215 if (elem_is_set (style
, MSTYLE_FONT_NAME
))
216 hash
^= GPOINTER_TO_UINT (style
->font_detail
.name
);
219 if (elem_is_set (style
, MSTYLE_FONT_BOLD
))
220 hash
^= (style
->font_detail
.bold
? 1 : 2);
223 if (elem_is_set (style
, MSTYLE_FONT_ITALIC
))
224 hash
^= (style
->font_detail
.italic
? 1 : 2);
227 if (elem_is_set (style
, MSTYLE_FONT_UNDERLINE
))
228 hash
^= (style
->font_detail
.underline
? 1 : 2);
231 if (elem_is_set (style
, MSTYLE_FONT_STRIKETHROUGH
))
232 hash
^= (style
->font_detail
.strikethrough
? 1 : 2);
235 if (elem_is_set (style
, MSTYLE_FONT_SCRIPT
))
236 hash
^= (style
->font_detail
.script
+ 0x100);
239 if (elem_is_set (style
, MSTYLE_FONT_SIZE
))
240 hash
^= ((int)(style
->font_detail
.size
* 97));
243 if (elem_is_set (style
, MSTYLE_FORMAT
))
244 hash
^= GPOINTER_TO_UINT (style
->format
);
247 if (elem_is_set (style
, MSTYLE_ALIGN_H
))
248 hash
^= (style
->h_align
+ 0x100);
251 if (elem_is_set (style
, MSTYLE_ALIGN_V
))
252 hash
^= (style
->v_align
+ 0x100);
255 if (elem_is_set (style
, MSTYLE_INDENT
))
256 hash
^= style
->indent
;
259 if (elem_is_set (style
, MSTYLE_ROTATION
))
260 hash
^= style
->rotation
;
263 if (elem_is_set (style
, MSTYLE_TEXT_DIR
))
264 hash
^= (style
->text_dir
+ 0x100);
267 if (elem_is_set (style
, MSTYLE_WRAP_TEXT
))
268 hash
^= (style
->wrap_text
? 1 : 2);
271 if (elem_is_set (style
, MSTYLE_SHRINK_TO_FIT
))
272 hash
^= (style
->shrink_to_fit
? 1 : 2);
275 if (elem_is_set (style
, MSTYLE_CONTENTS_LOCKED
))
276 hash
^= (style
->contents_locked
? 1 : 2);
279 if (elem_is_set (style
, MSTYLE_CONTENTS_HIDDEN
))
280 hash
^= (style
->contents_hidden
? 1 : 2);
283 style
->hash_key_xl
= (guint32
)hash
;
285 /* From here on, fields are not in MS XL */
287 if (elem_is_set (style
, MSTYLE_VALIDATION
)) {
289 * The hash used must not depend on the expressions inside
292 hash
^= (style
->validation
!= NULL
? 1 : 2);
296 if (elem_is_set (style
, MSTYLE_HLINK
))
297 hash
^= GPOINTER_TO_UINT (style
->hlink
);
300 if (elem_is_set (style
, MSTYLE_INPUT_MSG
))
301 hash
^= GPOINTER_TO_UINT (style
->input_msg
);
304 if (elem_is_set (style
, MSTYLE_CONDITIONS
)) {
306 * The hash used must not depend on the expressions inside
309 hash
^= style
->conditions
310 ? gnm_style_conditions_hash (style
->conditions
)
315 style
->hash_key
= (guint32
)hash
;
317 if (G_UNLIKELY (style
->set
== 0)) {
319 * gnm_style_new and gnm_style_dup both assume that the
320 * correct hash values (both of them) for the empty style
323 g_assert (style
->hash_key
== 0);
324 g_assert (style
->hash_key_xl
== 0);
331 gnm_style_hash_XL (gconstpointer style
)
333 if (((GnmStyle
const *)style
)->changed
)
334 gnm_style_update ((GnmStyle
*)style
);
335 return ((GnmStyle
const *)style
)->hash_key_xl
;
339 gnm_style_hash (gconstpointer style
)
341 if (((GnmStyle
const *)style
)->changed
)
342 gnm_style_update ((GnmStyle
*)style
);
343 return ((GnmStyle
const *)style
)->hash_key
;
346 #define ELEM_IS_EQ(a,b,elem) \
347 (elem == MSTYLE_COLOR_BACK \
348 ? a->color.back == b->color.back || (a->color.back->is_auto && b->color.back->is_auto) \
349 : (elem == MSTYLE_COLOR_PATTERN \
350 ? a->color.pattern == b->color.pattern || (a->color.pattern->is_auto && b->color.pattern->is_auto) \
351 : (elem >= MSTYLE_BORDER_TOP && elem <= MSTYLE_BORDER_DIAGONAL) \
352 ? a->borders[elem - MSTYLE_BORDER_TOP] == b->borders[elem - MSTYLE_BORDER_TOP] \
353 : (elem == MSTYLE_PATTERN \
354 ? a->pattern == b->pattern \
355 : (elem == MSTYLE_FONT_COLOR \
356 ? a->color.font == b->color.font || (a->color.font->is_auto && b->color.font->is_auto) \
357 : (elem == MSTYLE_FONT_NAME \
358 ? a->font_detail.name == b->font_detail.name \
359 : (elem == MSTYLE_FONT_BOLD \
360 ? a->font_detail.bold == b->font_detail.bold \
361 : (elem == MSTYLE_FONT_ITALIC \
362 ? a->font_detail.italic == b->font_detail.italic \
363 : (elem == MSTYLE_FONT_UNDERLINE \
364 ? a->font_detail.underline == b->font_detail.underline \
365 : (elem == MSTYLE_FONT_STRIKETHROUGH \
366 ? a->font_detail.strikethrough == b->font_detail.strikethrough \
367 : (elem == MSTYLE_FONT_SCRIPT \
368 ? a->font_detail.script == b->font_detail.script \
369 : (elem == MSTYLE_FONT_SIZE \
370 ? a->font_detail.size == b->font_detail.size \
371 : (elem == MSTYLE_FORMAT \
372 ? a->format == b->format \
373 : (elem == MSTYLE_ALIGN_V \
374 ? a->v_align == b->v_align \
375 : (elem == MSTYLE_ALIGN_H \
376 ? a->h_align == b->h_align \
377 : (elem == MSTYLE_INDENT \
378 ? a->indent == b->indent \
379 : (elem == MSTYLE_ROTATION \
380 ? a->rotation == b->rotation \
381 : (elem == MSTYLE_TEXT_DIR \
382 ? a->text_dir == b->text_dir \
383 : (elem == MSTYLE_WRAP_TEXT \
384 ? a->wrap_text == b->wrap_text \
385 : (elem == MSTYLE_SHRINK_TO_FIT \
386 ? a->shrink_to_fit == b->shrink_to_fit \
387 : (elem == MSTYLE_CONTENTS_LOCKED \
388 ? a->contents_locked == b->contents_locked \
389 : (elem == MSTYLE_CONTENTS_HIDDEN \
390 ? a->contents_hidden == b->contents_hidden \
391 : (elem == MSTYLE_VALIDATION \
392 ? a->validation == b->validation \
393 : (elem == MSTYLE_HLINK \
394 ? a->hlink == b->hlink \
395 : (elem == MSTYLE_INPUT_MSG \
396 ? a->input_msg == b->input_msg \
397 : (elem == MSTYLE_CONDITIONS \
398 ? (a->conditions == b->conditions || \
399 (a->conditions && b->conditions && \
400 gnm_style_conditions_equal (a->conditions, b->conditions, FALSE))) \
401 : FALSE)))))))))))))))))))))))))
404 * Note: the above is suboptimal for validation, hlink, input_msg.
406 * We are comparing pointers (which at least safely matches what we do
407 * with the hash), but I think we want proper equality.
411 elem_is_eq (GnmStyle
const *a
, GnmStyle
const *b
, GnmStyleElement elem
)
413 return ELEM_IS_EQ (a
, b
, elem
);
417 elem_assign_contents (GnmStyle
*dst
, GnmStyle
const *src
, GnmStyleElement elem
)
420 g_return_if_fail (src
!= dst
);
421 g_return_if_fail (elem_is_set (src
, elem
));
424 case MSTYLE_COLOR_BACK
: style_color_ref (dst
->color
.back
= src
->color
.back
); return;
425 case MSTYLE_COLOR_PATTERN
: style_color_ref (dst
->color
.pattern
= src
->color
.pattern
); return;
426 case MSTYLE_ANY_BORDER
:
427 elem
-= MSTYLE_BORDER_TOP
;
428 gnm_style_border_ref (dst
->borders
[elem
] = src
->borders
[elem
]);
430 case MSTYLE_PATTERN
: dst
->pattern
= src
->pattern
; return;
431 case MSTYLE_FONT_COLOR
: style_color_ref (dst
->color
.font
= src
->color
.font
); return;
432 case MSTYLE_FONT_NAME
: go_string_ref (dst
->font_detail
.name
= src
->font_detail
.name
); return;
433 case MSTYLE_FONT_BOLD
: dst
->font_detail
.bold
= src
->font_detail
.bold
; return;
434 case MSTYLE_FONT_ITALIC
: dst
->font_detail
.italic
= src
->font_detail
.italic
; return;
435 case MSTYLE_FONT_UNDERLINE
: dst
->font_detail
.underline
= src
->font_detail
.underline
; return;
436 case MSTYLE_FONT_STRIKETHROUGH
: dst
->font_detail
.strikethrough
= src
->font_detail
.strikethrough
; return;
437 case MSTYLE_FONT_SCRIPT
: dst
->font_detail
.script
= src
->font_detail
.script
; return;
438 case MSTYLE_FONT_SIZE
: dst
->font_detail
.size
= src
->font_detail
.size
; return;
439 case MSTYLE_FORMAT
: go_format_ref (dst
->format
= src
->format
); return;
440 case MSTYLE_ALIGN_V
: dst
->v_align
= src
->v_align
; return;
441 case MSTYLE_ALIGN_H
: dst
->h_align
= src
->h_align
; return;
442 case MSTYLE_INDENT
: dst
->indent
= src
->indent
; return;
443 case MSTYLE_ROTATION
: dst
->rotation
= src
->rotation
; return;
444 case MSTYLE_TEXT_DIR
: dst
->text_dir
= src
->text_dir
; return;
445 case MSTYLE_WRAP_TEXT
: dst
->wrap_text
= src
->wrap_text
; return;
446 case MSTYLE_SHRINK_TO_FIT
: dst
->shrink_to_fit
= src
->shrink_to_fit
; return;
447 case MSTYLE_CONTENTS_LOCKED
: dst
->contents_locked
= src
->contents_locked
; return;
448 case MSTYLE_CONTENTS_HIDDEN
: dst
->contents_hidden
= src
->contents_hidden
; return;
449 case MSTYLE_VALIDATION
:
450 if ((dst
->validation
= src
->validation
))
451 gnm_validation_ref (dst
->validation
);
454 if ((dst
->hlink
= src
->hlink
))
455 g_object_ref (dst
->hlink
);
457 case MSTYLE_INPUT_MSG
:
458 if ((dst
->input_msg
= src
->input_msg
))
459 g_object_ref (dst
->input_msg
);
461 case MSTYLE_CONDITIONS
:
462 if ((dst
->conditions
= src
->conditions
))
463 g_object_ref (dst
->conditions
);
471 elem_clear_contents (GnmStyle
*style
, GnmStyleElement elem
)
474 g_return_if_fail (style
!= NULL
);
476 if (!elem_is_set (style
, elem
))
480 case MSTYLE_COLOR_BACK
: style_color_unref (style
->color
.back
); return;
481 case MSTYLE_COLOR_PATTERN
: style_color_unref (style
->color
.pattern
); return;
482 case MSTYLE_ANY_BORDER
:
483 gnm_style_border_unref (style
->borders
[elem
- MSTYLE_BORDER_TOP
]);
485 case MSTYLE_FONT_COLOR
: style_color_unref (style
->color
.font
); return;
486 case MSTYLE_FONT_NAME
: go_string_unref (style
->font_detail
.name
); return;
487 case MSTYLE_FORMAT
: go_format_unref (style
->format
); return;
488 case MSTYLE_VALIDATION
:
489 if (style
->validation
)
490 gnm_validation_unref (style
->validation
);
494 g_object_unref (style
->hlink
);
496 case MSTYLE_INPUT_MSG
:
497 if (style
->input_msg
)
498 g_object_unref (style
->input_msg
);
500 case MSTYLE_CONDITIONS
:
501 if (style
->conditions
) {
502 clear_conditional_merges (style
);
503 g_object_unref (style
->conditions
);
512 * gnm_style_find_conflicts :
513 * @accum: accumulator #GnmStyle
514 * @overlay: #GnmStyle
517 * Copy any items from @overlay that do not conflict with the values in @accum.
518 * If an element had a previous conflict (flagged via @conflicts) it is ignored.
520 * Returns @conflicts with any new conflicts added.
523 gnm_style_find_conflicts (GnmStyle
*accum
, GnmStyle
const *overlay
,
524 unsigned int conflicts
)
528 g_assert (MSTYLE_ELEMENT_MAX
<= CHAR_BIT
* sizeof (conflicts
));
530 for (i
= 0; i
< MSTYLE_ELEMENT_MAX
; i
++) {
531 if (conflicts
& (1u << i
) || !elem_is_set (overlay
, i
)) {
533 } else if (!elem_is_set (accum
, i
)) {
534 elem_assign_contents (accum
, overlay
, i
);
536 elem_changed (accum
, i
);
537 } else if (!elem_is_eq (accum
, overlay
, i
))
538 conflicts
|= (1u << i
);
544 #define GNM_INPUT_MSG_EQUAL3(a,b,r) (gnm_input_msg_equal (a,b))
546 #define RELAX_CHECK(op_,field_,checker_) do { \
547 if (diffs & (1u << (op_)) && \
548 elem_is_set (a, (op_)) && \
549 elem_is_set (b, (op_)) && \
550 ((a->field_ == NULL) != (b->field_ == NULL) || \
551 checker_ (a->field_, b->field_, relax_sheet))) \
552 diffs &= ~(1u << (op_)); \
556 * gnm_style_find_differences:
559 * @relax_sheet: if %TRUE, ignore differences solely caused by being linked into different sheets.
561 * Determine how two fully-qualified styles differ.
563 * Returns differences as a bitset of #GnmStyleElement.
566 gnm_style_find_differences (GnmStyle
const *a
, GnmStyle
const *b
,
567 gboolean relax_sheet
)
570 unsigned int diffs
= 0;
572 g_assert (MSTYLE_ELEMENT_MAX
<= CHAR_BIT
* sizeof (diffs
));
574 for (i
= 0; i
< MSTYLE_ELEMENT_MAX
; i
++) {
575 if (elem_is_set (a
, i
) != elem_is_set (b
, i
) ||
576 (elem_is_set (a
, i
) && !elem_is_eq (a
, b
, i
)))
581 RELAX_CHECK (MSTYLE_HLINK
, hlink
, gnm_hlink_equal
);
582 RELAX_CHECK (MSTYLE_VALIDATION
, validation
, gnm_validation_equal
);
583 RELAX_CHECK (MSTYLE_INPUT_MSG
, input_msg
, GNM_INPUT_MSG_EQUAL3
);
584 RELAX_CHECK (MSTYLE_CONDITIONS
, conditions
, gnm_style_conditions_equal
);
591 #undef GNM_INPUT_MSG_EQUAL3
594 gnm_style_clear_pango (GnmStyle
*style
)
596 if (style
->pango_attrs
) {
597 pango_attr_list_unref (style
->pango_attrs
);
598 style
->pango_attrs
= NULL
;
604 gnm_style_clear_font (GnmStyle
*style
)
607 gnm_font_unref (style
->font
);
610 g_clear_object (&style
->font_context
);
616 * Caller is responsible for unrefing the result.
618 * Returns a new style with _no_ elements set.
623 GnmStyle
*style
= CHUNK_ALLOC0 (GnmStyle
, gnm_style_pool
);
625 style
->ref_count
= 1;
626 style
->link_count
= 0;
627 style
->linked_sheet
= NULL
;
628 style
->pango_attrs
= NULL
;
630 style
->validation
= NULL
;
632 style
->set
= style
->changed
= 0;
633 style
->validation
= NULL
;
635 style
->input_msg
= NULL
;
636 style
->conditions
= NULL
;
638 d(("new %p\n", style
));
644 * gnm_style_new_default:
646 * Caller is responsible for unrefing the result.
648 * Return value: a new style initialized to the default state.
651 gnm_style_new_default (void)
653 GnmStyle
*new_style
= gnm_style_new ();
656 gnm_style_set_font_name (new_style
, gnm_conf_get_core_defaultfont_name ());
657 gnm_style_set_font_size (new_style
, gnm_conf_get_core_defaultfont_size ());
658 gnm_style_set_font_bold (new_style
, gnm_conf_get_core_defaultfont_bold ());
659 gnm_style_set_font_italic (new_style
, gnm_conf_get_core_defaultfont_italic ());
661 gnm_style_set_format (new_style
, go_format_general ());
662 gnm_style_set_align_v (new_style
, GNM_VALIGN_BOTTOM
);
663 gnm_style_set_align_h (new_style
, GNM_HALIGN_GENERAL
);
664 gnm_style_set_indent (new_style
, 0);
665 gnm_style_set_rotation (new_style
, 0);
666 gnm_style_set_text_dir (new_style
, GNM_TEXT_DIR_CONTEXT
);
667 gnm_style_set_wrap_text (new_style
, FALSE
);
668 gnm_style_set_shrink_to_fit (new_style
, FALSE
);
669 gnm_style_set_contents_locked (new_style
, TRUE
);
670 gnm_style_set_contents_hidden (new_style
, FALSE
);
671 gnm_style_set_font_uline (new_style
, UNDERLINE_NONE
);
672 gnm_style_set_font_strike (new_style
, FALSE
);
673 gnm_style_set_font_script (new_style
, GO_FONT_SCRIPT_STANDARD
);
675 gnm_style_set_validation (new_style
, NULL
);
676 gnm_style_set_hlink (new_style
, NULL
);
677 gnm_style_set_input_msg (new_style
, NULL
);
678 gnm_style_set_conditions (new_style
, NULL
);
680 gnm_style_set_font_color (new_style
, style_color_black ());
681 gnm_style_set_back_color (new_style
, style_color_auto_back ());
682 gnm_style_set_pattern_color (new_style
, style_color_black ());
684 for (i
= MSTYLE_BORDER_TOP
; i
<= MSTYLE_BORDER_DIAGONAL
; ++i
)
685 gnm_style_set_border (new_style
, i
,
686 gnm_style_border_ref (gnm_style_border_none ()));
687 gnm_style_set_pattern (new_style
, 0);
693 gnm_style_dup (GnmStyle
const *src
)
695 GnmStyle
*new_style
= CHUNK_ALLOC0 (GnmStyle
, gnm_style_pool
);
698 new_style
->ref_count
= 1;
699 for (i
= 0; i
< MSTYLE_ELEMENT_MAX
; i
++)
700 if (elem_is_set (src
, i
)) {
701 elem_assign_contents (new_style
, src
, i
);
702 elem_set (new_style
, i
);
703 elem_changed (new_style
, i
);
706 if ((new_style
->pango_attrs
= src
->pango_attrs
)) {
707 pango_attr_list_ref (new_style
->pango_attrs
);
708 new_style
->pango_attrs_zoom
= src
->pango_attrs_zoom
;
711 if ((new_style
->font
= src
->font
)) {
712 gnm_font_ref (new_style
->font
);
713 new_style
->font_context
= g_object_ref (src
->font_context
);
716 d(("dup %p\n", new_style
));
721 * gnm_style_new_merged :
723 * @overlay: #GnmStyle
725 * A new GnmStyle that contains any elements of @overlay that are set, and uses
726 * @base for anything that is not set in @overlay.
728 * Returns: (transfer full): A ref to a new GnmStyle.
731 gnm_style_new_merged (GnmStyle
const *base
, GnmStyle
const *overlay
)
733 GnmStyle
*new_style
= CHUNK_ALLOC0 (GnmStyle
, gnm_style_pool
);
736 new_style
->ref_count
= 1;
737 for (i
= 0; i
< MSTYLE_ELEMENT_MAX
; i
++) {
738 if (elem_is_set (overlay
, i
))
739 elem_assign_contents (new_style
, overlay
, i
);
740 else if (elem_is_set (base
, i
))
741 elem_assign_contents (new_style
, base
, i
);
744 elem_set (new_style
, i
);
745 elem_changed (new_style
, i
);
747 d(("copy merge %p\n", new_style
));
752 gnm_style_ref (GnmStyle
const *style
)
754 g_return_if_fail (style
!= NULL
);
755 g_return_if_fail (style
->ref_count
> 0);
757 ((GnmStyle
*)style
)->ref_count
++;
758 d(("ref %p = %d\n", style
, style
->ref_count
));
763 * @style: #GnmStyle const
765 * Unrefs and _potentially frees_ @style.
766 * Takes a _const_ pointer to facilitate life cycles. The const indicates that
767 * the content can not be changed, mainly when handling styles that are in the
771 gnm_style_unref (GnmStyle
const *style
)
773 g_return_if_fail (style
!= NULL
);
774 g_return_if_fail (style
->ref_count
> 0);
776 d(("unref %p = %d\n", style
, style
->ref_count
-1));
777 if (((GnmStyle
*)style
)->ref_count
-- <= 1) {
778 GnmStyle
*unconst
= (GnmStyle
*)style
;
781 g_return_if_fail (style
->link_count
== 0);
782 g_return_if_fail (style
->linked_sheet
== NULL
);
784 for (i
= 0; i
< MSTYLE_ELEMENT_MAX
; i
++)
785 elem_clear_contents (unconst
, i
);
787 clear_conditional_merges (unconst
);
788 gnm_style_clear_pango (unconst
);
789 gnm_style_clear_font (unconst
);
792 if (style
->deps
->len
> 0)
793 g_warning ("Leftover style deps!");
794 g_ptr_array_free (style
->deps
, TRUE
);
797 CHUNK_FREE (gnm_style_pool
, unconst
);
802 gnm_style_get_type (void)
807 t
= g_boxed_type_register_static ("GnmStyle",
808 (GBoxedCopyFunc
)gnm_style_ref
,
809 (GBoxedFreeFunc
)gnm_style_unref
);
815 * Replace auto pattern color in style with sheet's auto pattern color.
816 * make_copy tells if we are allowed to modify the style in place or we must
820 link_pattern_color (GnmStyle
*style
, GnmColor
*auto_color
, gboolean make_copy
)
822 GnmColor
*pattern_color
= style
->color
.pattern
;
824 if (pattern_color
->is_auto
&& auto_color
!= pattern_color
) {
825 style_color_ref (auto_color
);
827 GnmStyle
*orig
= style
;
828 style
= gnm_style_dup (style
);
829 gnm_style_unref (orig
);
831 gnm_style_set_pattern_color (style
, auto_color
);
837 * Replace auto border colors in style with sheet's auto pattern
838 * color. (pattern is *not* a typo.)
839 * make_copy tells if we are allowed to modify the style in place or we must
842 * FIXME: We conjecture that XL color 64 in border should change with the
843 * pattern, but not color 127. That distinction is not yet represented in
844 * our data structures.
847 link_border_colors (GnmStyle
*style
, GnmColor
*auto_color
, gboolean make_copy
)
851 for (i
= MSTYLE_BORDER_TOP
; i
<= MSTYLE_BORDER_DIAGONAL
; ++i
) {
852 if (elem_is_set (style
, i
)) {
854 style
->borders
[i
- MSTYLE_BORDER_TOP
];
860 color
= border
->color
;
861 if (color
->is_auto
&& auto_color
!= color
) {
862 GnmBorder
*new_border
;
863 GnmStyleBorderOrientation orientation
;
866 case MSTYLE_BORDER_LEFT
:
867 case MSTYLE_BORDER_RIGHT
:
868 orientation
= GNM_STYLE_BORDER_VERTICAL
;
870 case MSTYLE_BORDER_REV_DIAGONAL
:
871 case MSTYLE_BORDER_DIAGONAL
:
872 orientation
= GNM_STYLE_BORDER_DIAGONAL
;
874 case MSTYLE_BORDER_TOP
:
875 case MSTYLE_BORDER_BOTTOM
:
877 orientation
= GNM_STYLE_BORDER_HORIZONTAL
;
880 style_color_ref (auto_color
);
881 new_border
= gnm_style_border_fetch (
882 border
->line_type
, auto_color
,
886 GnmStyle
*orig
= style
;
887 style
= gnm_style_dup (style
);
888 gnm_style_unref (orig
);
891 gnm_style_set_border (style
, i
, new_border
);
899 gnm_style_linked_sheet_changed (GnmStyle
*style
)
901 Sheet
*sheet
= style
->linked_sheet
;
903 if (elem_is_set (style
, MSTYLE_VALIDATION
) &&
905 gnm_validation_get_sheet (style
->validation
) != sheet
) {
906 GnmValidation
*new_v
= gnm_validation_dup (style
->validation
);
907 gnm_validation_set_sheet (new_v
, sheet
);
908 gnm_style_set_validation (style
, new_v
);
911 if (elem_is_set (style
, MSTYLE_HLINK
) &&
913 gnm_hlink_get_sheet (style
->hlink
) != sheet
) {
914 GnmHLink
*new_l
= gnm_hlink_dup (style
->hlink
);
915 gnm_hlink_set_sheet (new_l
, sheet
);
916 gnm_style_set_hlink (style
, new_l
);
919 if (elem_is_set (style
, MSTYLE_CONDITIONS
) &&
921 gnm_style_conditions_get_sheet (style
->conditions
) != sheet
) {
922 GnmStyleConditions
*new_c
= gnm_style_conditions_dup (style
->conditions
);
923 gnm_style_conditions_set_sheet (new_c
, sheet
);
924 gnm_style_set_conditions (style
, new_c
);
929 * gnm_style_link_sheet :
933 * ABSORBS a reference to the style and sets the link count to 1.
935 * Where auto pattern color occurs in the style (it may for pattern and
936 * borders), it is replaced with the sheet's auto pattern color. We make
937 * sure that we do not modify the style which was passed in to us, but also
938 * that we don't copy more than once. The final argument to the
939 * link_xxxxx_color functions tell whether or not to copy.
942 gnm_style_link_sheet (GnmStyle
*style
, Sheet
*sheet
)
944 GnmColor
*auto_color
;
945 gboolean style_is_orig
= TRUE
;
947 if (style
->linked_sheet
!= NULL
) {
948 GnmStyle
*orig
= style
;
949 style
= gnm_style_dup (style
);
950 gnm_style_unref (orig
);
951 style_is_orig
= FALSE
;
954 g_return_val_if_fail (style
->linked_sheet
!= sheet
, style
);
957 g_return_val_if_fail (style
->link_count
== 0, style
);
958 g_return_val_if_fail (style
->linked_sheet
== NULL
, style
);
960 auto_color
= sheet_style_get_auto_pattern_color (sheet
);
961 if (elem_is_set (style
, MSTYLE_COLOR_PATTERN
))
962 style
= link_pattern_color (style
, auto_color
, style_is_orig
);
963 style
= link_border_colors (style
, auto_color
, style_is_orig
);
964 style_color_unref (auto_color
);
966 style
->linked_sheet
= sheet
;
967 style
->link_count
= 1;
969 gnm_style_linked_sheet_changed (style
);
971 d(("link sheet %p = 1\n", style
));
976 gnm_style_link (GnmStyle
*style
)
978 g_return_if_fail (style
->link_count
> 0);
981 d(("link %p = %d\n", style
, style
->link_count
));
985 gnm_style_link_multiple (GnmStyle
*style
, int count
)
987 g_return_if_fail (style
->link_count
> 0);
989 style
->link_count
+= count
;
990 d(("multiple link %p + %d = %d\n", style
, count
, style
->link_count
));
994 gnm_style_unlink (GnmStyle
*style
)
996 g_return_if_fail (style
->link_count
> 0);
998 d(("unlink %p = %d\n", style
, style
->link_count
-1));
999 if (style
->link_count
-- == 1) {
1000 sheet_style_unlink (style
->linked_sheet
, style
);
1001 style
->linked_sheet
= NULL
;
1002 gnm_style_unref (style
);
1007 gnm_style_eq (GnmStyle
const *a
, GnmStyle
const *b
)
1013 gnm_style_equal (GnmStyle
const *a
, GnmStyle
const *b
)
1019 if (a
->set
!= b
->set
|| !gnm_style_equal_XL (a
, b
))
1021 UNROLLED_FOR (i
= MSTYLE_VALIDATION
, i
< MSTYLE_ELEMENT_MAX
, i
++, {
1022 if (elem_is_set (a
, i
) && !ELEM_IS_EQ (a
, b
, i
))
1030 gnm_style_equal_XL (GnmStyle
const *a
, GnmStyle
const *b
)
1034 g_return_val_if_fail (a
!= NULL
, FALSE
);
1035 g_return_val_if_fail (b
!= NULL
, FALSE
);
1040 if ((a
->set
^ b
->set
) & ((1u << MSTYLE_VALIDATION
) - 1))
1043 UNROLLED_FOR (i
= MSTYLE_COLOR_BACK
, i
< MSTYLE_VALIDATION
, i
++, {
1044 if (elem_is_set (a
, i
) && !ELEM_IS_EQ (a
, b
, i
))
1051 * gnm_style_equal_elem:
1056 * Returns: %TRUE, if the two styles have the same contents for the
1057 * given element, either because neither have it set, or because both
1058 * have it set and to the same value.
1061 gnm_style_equal_elem (GnmStyle
const *a
, GnmStyle
const *b
, GnmStyleElement e
)
1063 if (elem_is_set (a
, e
))
1064 return elem_is_set (b
, e
) && elem_is_eq (a
, b
, e
);
1066 return !elem_is_set (b
, e
);
1071 #define CMP_TRY_NUMBER_RAW(a_,b_) \
1073 if ((a_) < (b_)) return -1; \
1074 if ((a_) > (b_)) return -1; \
1077 #define CMP_TRY_NUMBER(e_,f_) \
1079 if (elem_is_set (a, (e_))) \
1080 CMP_TRY_NUMBER_RAW(a->f_, b->f_); \
1083 #define CMP_TRY_COLOR(e_,f_) \
1085 if (elem_is_set (a, (e_))) { \
1086 CMP_TRY_NUMBER_RAW(a->f_->is_auto, b->f_->is_auto); \
1087 CMP_TRY_NUMBER_RAW(a->f_->go_color, b->f_->go_color); \
1092 * Ordering of GnmStyles. Apart from FIXMEs, this shouldn't change
1093 * from one run to the next.
1096 gnm_style_cmp (GnmStyle
const *a
, GnmStyle
const *b
)
1104 * Very quick comparison based on what is set. This also allows
1105 * us to check on one elem_is_set below.
1107 CMP_TRY_NUMBER_RAW (a
->set
, b
->set
);
1109 CMP_TRY_COLOR (MSTYLE_FONT_COLOR
, color
.font
);
1110 CMP_TRY_COLOR (MSTYLE_COLOR_BACK
, color
.back
);
1111 CMP_TRY_COLOR (MSTYLE_COLOR_PATTERN
, color
.pattern
);
1112 for (e
= MSTYLE_BORDER_TOP
; e
<= MSTYLE_BORDER_DIAGONAL
; e
++) {
1113 GnmBorder
const *ba
, *bb
;
1114 if (!elem_is_set (a
, e
))
1116 ba
= a
->borders
[e
- MSTYLE_BORDER_TOP
];
1117 bb
= b
->borders
[e
- MSTYLE_BORDER_TOP
];
1119 continue; /* Handles both being NULL */
1120 CMP_TRY_NUMBER_RAW(!!ba
, !!bb
);
1121 CMP_TRY_NUMBER_RAW(ba
->line_type
, bb
->line_type
);
1122 CMP_TRY_NUMBER_RAW(ba
->color
->go_color
, bb
->color
->go_color
);
1123 CMP_TRY_NUMBER_RAW(ba
->begin_margin
, bb
->begin_margin
);
1124 CMP_TRY_NUMBER_RAW(ba
->end_margin
, bb
->end_margin
);
1125 CMP_TRY_NUMBER_RAW(ba
->width
, bb
->width
);
1127 CMP_TRY_NUMBER (MSTYLE_PATTERN
, pattern
);
1128 if (elem_is_set (a
, MSTYLE_FONT_NAME
)) {
1129 /* Plain strcmp, not utf-8. We need to see diffs. */
1130 int tmp
= strcmp (a
->font_detail
.name
->str
,
1131 b
->font_detail
.name
->str
);
1135 CMP_TRY_NUMBER (MSTYLE_FONT_BOLD
, font_detail
.bold
);
1136 CMP_TRY_NUMBER (MSTYLE_FONT_ITALIC
, font_detail
.italic
);
1137 CMP_TRY_NUMBER (MSTYLE_FONT_UNDERLINE
, font_detail
.underline
);
1138 CMP_TRY_NUMBER (MSTYLE_FONT_STRIKETHROUGH
, font_detail
.strikethrough
);
1139 CMP_TRY_NUMBER (MSTYLE_FONT_SCRIPT
, font_detail
.script
);
1140 CMP_TRY_NUMBER (MSTYLE_FONT_SIZE
, font_detail
.size
);
1141 if (elem_is_set (a
, MSTYLE_FORMAT
)) {
1142 /* Plain strcmp, not utf-8. We need to see diffs. */
1143 int tmp
= strcmp (go_format_as_XL (a
->format
),
1144 go_format_as_XL (b
->format
));
1148 CMP_TRY_NUMBER (MSTYLE_ALIGN_H
, h_align
);
1149 CMP_TRY_NUMBER (MSTYLE_ALIGN_V
, v_align
);
1150 CMP_TRY_NUMBER (MSTYLE_INDENT
, indent
);
1151 CMP_TRY_NUMBER (MSTYLE_ROTATION
, rotation
);
1152 CMP_TRY_NUMBER (MSTYLE_TEXT_DIR
, text_dir
);
1153 CMP_TRY_NUMBER (MSTYLE_WRAP_TEXT
, wrap_text
);
1154 CMP_TRY_NUMBER (MSTYLE_SHRINK_TO_FIT
, shrink_to_fit
);
1155 CMP_TRY_NUMBER (MSTYLE_CONTENTS_LOCKED
, contents_locked
);
1156 CMP_TRY_NUMBER (MSTYLE_CONTENTS_HIDDEN
, contents_hidden
);
1157 /* FIXME: validation */
1159 /* FIXME: input_msg */
1160 /* FIXME: conditions */
1161 /* FIXME: cond_styles */
1163 /* Last resort: pointer comparison. */
1164 return a
< b
? -1 : +1;
1167 #undef CMP_TRY_NUMBER
1168 #undef CMP_TRY_COLOR
1172 * gnm_style_equal_header :
1175 * @top: is this a header vertically or horizontally
1177 * Check to see if @a is different enough from @b to make us think that @a is
1181 gnm_style_equal_header (GnmStyle
const *a
, GnmStyle
const *b
, gboolean top
)
1183 int i
= top
? MSTYLE_BORDER_BOTTOM
: MSTYLE_BORDER_RIGHT
;
1185 if (!elem_is_eq (a
, b
, i
))
1187 for (i
= MSTYLE_COLOR_BACK
; i
<= MSTYLE_COLOR_PATTERN
; i
++)
1188 if (!elem_is_eq (a
, b
, i
))
1190 for (i
= MSTYLE_FONT_COLOR
; i
<= MSTYLE_SHRINK_TO_FIT
; i
++)
1191 if (!elem_is_eq (a
, b
, i
))
1198 gnm_style_is_element_set (GnmStyle
const *style
, GnmStyleElement elem
)
1200 g_return_val_if_fail (style
!= NULL
, FALSE
);
1201 g_return_val_if_fail (MSTYLE_COLOR_BACK
<= elem
&& elem
< MSTYLE_ELEMENT_MAX
, FALSE
);
1202 return elem_is_set (style
, elem
);
1206 * gnm_style_is_complete :
1209 * Returns TRUE if all elements are set.
1212 gnm_style_is_complete (GnmStyle
const *style
)
1214 g_return_val_if_fail (style
!= NULL
, FALSE
);
1216 return style
->set
== ((1u << MSTYLE_ELEMENT_MAX
) - 1);
1220 gnm_style_unset_element (GnmStyle
*style
, GnmStyleElement elem
)
1222 g_return_if_fail (style
!= NULL
);
1223 g_return_if_fail (MSTYLE_COLOR_BACK
<= elem
&& elem
< MSTYLE_ELEMENT_MAX
);
1225 if (elem_is_set (style
, elem
)) {
1226 elem_clear_contents (style
, elem
);
1227 elem_unset (style
, elem
);
1234 * @overlay: #GnmStyle
1236 * Applies all active elements of @overlay onto @base.
1239 gnm_style_merge (GnmStyle
*base
, GnmStyle
const *overlay
)
1242 if (base
== overlay
)
1244 for (i
= 0; i
< MSTYLE_ELEMENT_MAX
; i
++)
1245 if (elem_is_set (overlay
, i
)) {
1246 elem_clear_contents (base
, i
);
1247 elem_assign_contents (base
, overlay
, i
);
1248 elem_changed (base
, i
);
1253 * gnm_style_merge_element:
1254 * @dst: Destination style
1255 * @src: Source style
1256 * @elem: Element to replace
1258 * This function replaces element @elem in style @dst with element @elem
1259 * in style @src. (If element @elem was already set in style @dst then
1260 * the element will first be unset)
1263 gnm_style_merge_element (GnmStyle
*dst
, GnmStyle
const *src
, GnmStyleElement elem
)
1265 g_return_if_fail (src
!= NULL
);
1266 g_return_if_fail (dst
!= NULL
);
1267 g_return_if_fail (src
!= dst
);
1269 if (elem_is_set (src
, elem
)) {
1270 elem_clear_contents (dst
, elem
);
1271 elem_assign_contents (dst
, src
, elem
);
1272 elem_set (dst
, elem
);
1273 elem_changed (dst
, elem
);
1278 gnm_style_set_font_color (GnmStyle
*style
, GnmColor
*col
)
1280 g_return_if_fail (style
!= NULL
);
1281 g_return_if_fail (col
!= NULL
);
1283 elem_changed (style
, MSTYLE_FONT_COLOR
);
1284 if (elem_is_set (style
, MSTYLE_FONT_COLOR
))
1285 style_color_unref (style
->color
.font
);
1287 elem_set (style
, MSTYLE_FONT_COLOR
);
1288 elem_changed (style
, MSTYLE_FONT_COLOR
);
1289 style
->color
.font
= col
;
1290 gnm_style_clear_pango (style
);
1294 * gnm_style_set_back_color :
1298 * Assigns @col as the background of @style.
1300 * NOTE : the background colour is only visibile if
1301 * GnmStyle::pattern > 0
1304 gnm_style_set_back_color (GnmStyle
*style
, GnmColor
*col
)
1306 g_return_if_fail (style
!= NULL
);
1307 g_return_if_fail (col
!= NULL
);
1309 elem_changed (style
, MSTYLE_COLOR_BACK
);
1310 if (elem_is_set (style
, MSTYLE_COLOR_BACK
))
1311 style_color_unref (style
->color
.back
);
1313 elem_set (style
, MSTYLE_COLOR_BACK
);
1314 style
->color
.back
= col
;
1315 gnm_style_clear_pango (style
);
1318 gnm_style_set_pattern_color (GnmStyle
*style
, GnmColor
*col
)
1320 g_return_if_fail (style
!= NULL
);
1321 g_return_if_fail (col
!= NULL
);
1323 elem_changed (style
, MSTYLE_COLOR_PATTERN
);
1324 if (elem_is_set (style
, MSTYLE_COLOR_PATTERN
))
1325 style_color_unref (style
->color
.pattern
);
1327 elem_set (style
, MSTYLE_COLOR_PATTERN
);
1328 style
->color
.pattern
= col
;
1329 gnm_style_clear_pango (style
);
1333 gnm_style_get_font_color (GnmStyle
const *style
)
1335 g_return_val_if_fail (style
!= NULL
, NULL
);
1336 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_COLOR
), NULL
);
1337 return style
->color
.font
;
1341 gnm_style_get_back_color (GnmStyle
const *style
)
1343 g_return_val_if_fail (style
!= NULL
, NULL
);
1344 g_return_val_if_fail (elem_is_set (style
, MSTYLE_COLOR_BACK
), NULL
);
1345 return style
->color
.back
;
1349 gnm_style_get_pattern_color (GnmStyle
const *style
)
1351 g_return_val_if_fail (style
!= NULL
, NULL
);
1352 g_return_val_if_fail (elem_is_set (style
, MSTYLE_COLOR_PATTERN
), NULL
);
1353 return style
->color
.pattern
;
1357 gnm_style_set_border (GnmStyle
*style
, GnmStyleElement elem
,
1360 g_return_if_fail (style
!= NULL
);
1362 /* NOTE : It is legal for border to be NULL */
1364 case MSTYLE_ANY_BORDER
:
1365 elem_changed (style
, elem
);
1366 elem_set (style
, elem
);
1367 elem
-= MSTYLE_BORDER_TOP
;
1368 if (style
->borders
[elem
])
1369 gnm_style_border_unref (style
->borders
[elem
]);
1370 style
->borders
[elem
] = border
;
1373 g_warning ("Not a border element");
1379 gnm_style_get_border (GnmStyle
const *style
, GnmStyleElement elem
)
1381 g_return_val_if_fail (style
!= NULL
, NULL
);
1384 case MSTYLE_ANY_BORDER
:
1385 return style
->borders
[elem
- MSTYLE_BORDER_TOP
];
1388 g_warning ("Not a border element");
1394 gnm_style_set_pattern (GnmStyle
*style
, int pattern
)
1396 g_return_if_fail (style
!= NULL
);
1397 g_return_if_fail (pattern
>= 0);
1398 g_return_if_fail (pattern
< GNM_PATTERNS_MAX
);
1400 elem_changed (style
, MSTYLE_PATTERN
);
1401 elem_set (style
, MSTYLE_PATTERN
);
1402 style
->pattern
= pattern
;
1406 gnm_style_get_pattern (GnmStyle
const *style
)
1408 g_return_val_if_fail (style
!= NULL
, 0);
1409 g_return_val_if_fail (elem_is_set (style
, MSTYLE_PATTERN
), 0);
1411 return style
->pattern
;
1415 * gnm_style_get_font:
1417 * @context: #PangoContext
1419 * Returns: (transfer none):
1422 gnm_style_get_font (GnmStyle
const *style
, PangoContext
*context
)
1424 g_return_val_if_fail (style
!= NULL
, NULL
);
1426 if (!style
->font
|| style
->font_context
!= context
) {
1428 gboolean bold
, italic
;
1431 gnm_style_clear_font ((GnmStyle
*)style
);
1433 if (elem_is_set (style
, MSTYLE_FONT_NAME
))
1434 name
= gnm_style_get_font_name (style
);
1436 name
= DEFAULT_FONT
;
1438 if (elem_is_set (style
, MSTYLE_FONT_BOLD
))
1439 bold
= gnm_style_get_font_bold (style
);
1443 if (elem_is_set (style
, MSTYLE_FONT_ITALIC
))
1444 italic
= gnm_style_get_font_italic (style
);
1448 if (elem_is_set (style
, MSTYLE_FONT_SIZE
))
1449 size
= gnm_style_get_font_size (style
);
1451 size
= DEFAULT_SIZE
;
1453 ((GnmStyle
*)style
)->font
=
1454 gnm_font_new (context
, name
, size
, bold
, italic
);
1455 ((GnmStyle
*)style
)->font_context
= g_object_ref (context
);
1462 gnm_style_set_font_name (GnmStyle
*style
, char const *name
)
1464 g_return_if_fail (name
!= NULL
);
1465 g_return_if_fail (style
!= NULL
);
1467 elem_changed (style
, MSTYLE_FONT_NAME
);
1468 if (elem_is_set (style
, MSTYLE_FONT_NAME
))
1469 go_string_unref (style
->font_detail
.name
);
1471 elem_set (style
, MSTYLE_FONT_NAME
);
1472 style
->font_detail
.name
= go_string_new (name
);
1473 gnm_style_clear_font (style
);
1474 gnm_style_clear_pango (style
);
1478 gnm_style_get_font_name (GnmStyle
const *style
)
1480 g_return_val_if_fail (style
!= NULL
, NULL
);
1481 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_NAME
), NULL
);
1483 return style
->font_detail
.name
->str
;
1487 gnm_style_set_font_bold (GnmStyle
*style
, gboolean bold
)
1489 g_return_if_fail (style
!= NULL
);
1491 elem_changed (style
, MSTYLE_FONT_BOLD
);
1492 elem_set (style
, MSTYLE_FONT_BOLD
);
1493 style
->font_detail
.bold
= !!bold
;
1494 gnm_style_clear_font (style
);
1495 gnm_style_clear_pango (style
);
1499 gnm_style_get_font_bold (GnmStyle
const *style
)
1501 g_return_val_if_fail (style
!= NULL
, FALSE
);
1502 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_BOLD
), FALSE
);
1504 return style
->font_detail
.bold
;
1508 gnm_style_set_font_italic (GnmStyle
*style
, gboolean italic
)
1510 g_return_if_fail (style
!= NULL
);
1512 elem_changed (style
, MSTYLE_FONT_ITALIC
);
1513 elem_set (style
, MSTYLE_FONT_ITALIC
);
1514 style
->font_detail
.italic
= !!italic
;
1515 gnm_style_clear_font (style
);
1516 gnm_style_clear_pango (style
);
1520 gnm_style_get_font_italic (GnmStyle
const *style
)
1522 g_return_val_if_fail (style
!= NULL
, FALSE
);
1523 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_ITALIC
), FALSE
);
1525 return style
->font_detail
.italic
;
1529 gnm_style_set_font_uline (GnmStyle
*style
, GnmUnderline
const underline
)
1531 g_return_if_fail (style
!= NULL
);
1532 g_return_if_fail (underline
>= UNDERLINE_NONE
&& underline
<= UNDERLINE_DOUBLE_LOW
);
1534 elem_changed (style
, MSTYLE_FONT_UNDERLINE
);
1535 elem_set (style
, MSTYLE_FONT_UNDERLINE
);
1536 style
->font_detail
.underline
= underline
;
1537 gnm_style_clear_pango (style
);
1541 gnm_style_get_font_uline (GnmStyle
const *style
)
1543 g_return_val_if_fail (style
!= NULL
, UNDERLINE_NONE
);
1544 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_UNDERLINE
), UNDERLINE_NONE
);
1546 return style
->font_detail
.underline
;
1550 gnm_style_set_font_strike (GnmStyle
*style
, gboolean strikethrough
)
1552 g_return_if_fail (style
!= NULL
);
1554 elem_changed (style
, MSTYLE_FONT_STRIKETHROUGH
);
1555 elem_set (style
, MSTYLE_FONT_STRIKETHROUGH
);
1556 style
->font_detail
.strikethrough
= !!strikethrough
;
1557 gnm_style_clear_pango (style
);
1561 gnm_style_get_font_strike (GnmStyle
const *style
)
1563 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_STRIKETHROUGH
), FALSE
);
1565 return style
->font_detail
.strikethrough
;
1569 gnm_style_set_font_script (GnmStyle
*style
, GOFontScript script
)
1571 g_return_if_fail (style
!= NULL
);
1572 elem_changed (style
, MSTYLE_FONT_SCRIPT
);
1573 elem_set (style
, MSTYLE_FONT_SCRIPT
);
1574 style
->font_detail
.script
= script
;
1575 gnm_style_clear_pango (style
);
1579 gnm_style_get_font_script (GnmStyle
const *style
)
1581 g_return_val_if_fail (style
!= NULL
, GO_FONT_SCRIPT_STANDARD
);
1582 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_SCRIPT
), GO_FONT_SCRIPT_STANDARD
);
1584 return style
->font_detail
.script
;
1588 gnm_style_set_font_size (GnmStyle
*style
, double size
)
1590 g_return_if_fail (style
!= NULL
);
1591 g_return_if_fail (size
>= 1.);
1592 elem_changed (style
, MSTYLE_FONT_SIZE
);
1593 elem_set (style
, MSTYLE_FONT_SIZE
);
1594 style
->font_detail
.size
= size
;
1595 gnm_style_clear_font (style
);
1596 gnm_style_clear_pango (style
);
1600 gnm_style_get_font_size (GnmStyle
const *style
)
1602 g_return_val_if_fail (style
!= NULL
, 12.0);
1603 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_SIZE
), 12.0);
1605 return style
->font_detail
.size
;
1609 gnm_style_set_format (GnmStyle
*style
, GOFormat
const *format
)
1611 g_return_if_fail (style
!= NULL
);
1612 g_return_if_fail (format
!= NULL
);
1614 elem_changed (style
, MSTYLE_FORMAT
);
1615 go_format_ref (format
);
1616 elem_clear_contents (style
, MSTYLE_FORMAT
);
1617 elem_set (style
, MSTYLE_FORMAT
);
1618 style
->format
= format
;
1622 * gnm_style_set_format_text:
1624 * @style: mstyle to change.
1625 * @format: An *untranslated* format string.
1628 gnm_style_set_format_text (GnmStyle
*style
, char const *format
)
1632 g_return_if_fail (style
!= NULL
);
1633 g_return_if_fail (format
!= NULL
);
1635 sf
= go_format_new_from_XL (format
);
1636 gnm_style_set_format (style
, sf
);
1637 go_format_unref (sf
);
1641 gnm_style_get_format (GnmStyle
const *style
)
1643 g_return_val_if_fail (style
!= NULL
, NULL
);
1644 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FORMAT
), NULL
);
1646 return style
->format
;
1650 gnm_style_set_align_h (GnmStyle
*style
, GnmHAlign a
)
1652 g_return_if_fail (style
!= NULL
);
1654 elem_changed (style
, MSTYLE_ALIGN_H
);
1655 elem_set (style
, MSTYLE_ALIGN_H
);
1660 gnm_style_get_align_h (GnmStyle
const *style
)
1662 g_return_val_if_fail (style
!= NULL
, GNM_HALIGN_LEFT
);
1663 g_return_val_if_fail (elem_is_set (style
, MSTYLE_ALIGN_H
), GNM_HALIGN_LEFT
);
1665 return style
->h_align
;
1669 gnm_style_set_align_v (GnmStyle
*style
, GnmVAlign a
)
1671 g_return_if_fail (style
!= NULL
);
1673 elem_changed (style
, MSTYLE_ALIGN_V
);
1674 elem_set (style
, MSTYLE_ALIGN_V
);
1679 gnm_style_get_align_v (GnmStyle
const *style
)
1681 g_return_val_if_fail (style
!= NULL
, GNM_VALIGN_TOP
);
1682 g_return_val_if_fail (elem_is_set (style
, MSTYLE_ALIGN_V
), GNM_VALIGN_TOP
);
1684 return style
->v_align
;
1688 gnm_style_set_indent (GnmStyle
*style
, int i
)
1690 g_return_if_fail (style
!= NULL
);
1692 elem_changed (style
, MSTYLE_INDENT
);
1693 elem_set (style
, MSTYLE_INDENT
);
1698 gnm_style_get_indent (GnmStyle
const *style
)
1700 g_return_val_if_fail (style
!= NULL
, 0);
1701 g_return_val_if_fail (elem_is_set (style
, MSTYLE_INDENT
), 0);
1703 return style
->indent
;
1707 gnm_style_set_rotation (GnmStyle
*style
, int rot_deg
)
1709 g_return_if_fail (style
!= NULL
);
1711 elem_changed (style
, MSTYLE_ROTATION
);
1712 elem_set (style
, MSTYLE_ROTATION
);
1713 style
->rotation
= rot_deg
;
1717 gnm_style_get_rotation (GnmStyle
const *style
)
1719 g_return_val_if_fail (style
!= NULL
, 0);
1720 g_return_val_if_fail (elem_is_set (style
, MSTYLE_ROTATION
), 0);
1722 return style
->rotation
;
1726 gnm_style_set_text_dir (GnmStyle
*style
, GnmTextDir text_dir
)
1728 g_return_if_fail (style
!= NULL
);
1730 elem_changed (style
, MSTYLE_TEXT_DIR
);
1731 elem_set (style
, MSTYLE_TEXT_DIR
);
1732 style
->text_dir
= text_dir
;
1736 gnm_style_get_text_dir (GnmStyle
const *style
)
1738 g_return_val_if_fail (style
!= NULL
, GNM_TEXT_DIR_CONTEXT
);
1739 g_return_val_if_fail (elem_is_set (style
, MSTYLE_TEXT_DIR
), GNM_TEXT_DIR_CONTEXT
);
1741 return style
->text_dir
;
1745 gnm_style_set_wrap_text (GnmStyle
*style
, gboolean f
)
1747 g_return_if_fail (style
!= NULL
);
1749 elem_changed (style
, MSTYLE_WRAP_TEXT
);
1750 elem_set (style
, MSTYLE_WRAP_TEXT
);
1751 style
->wrap_text
= !!f
;
1755 gnm_style_get_wrap_text (GnmStyle
const *style
)
1757 g_return_val_if_fail (elem_is_set (style
, MSTYLE_WRAP_TEXT
), FALSE
);
1759 return style
->wrap_text
;
1763 * Same as gnm_style_get_wrap_text except that if either halign or valign
1764 * is _JUSTIFY, the result will be TRUE.
1767 gnm_style_get_effective_wrap_text (GnmStyle
const *style
)
1769 g_return_val_if_fail (style
!= NULL
, FALSE
);
1770 g_return_val_if_fail (elem_is_set (style
, MSTYLE_WRAP_TEXT
), FALSE
);
1771 g_return_val_if_fail (elem_is_set (style
, MSTYLE_ALIGN_V
), FALSE
);
1772 g_return_val_if_fail (elem_is_set (style
, MSTYLE_ALIGN_H
), FALSE
);
1774 /* Note: GNM_HALIGN_GENERAL never expands to GNM_HALIGN_JUSTIFY. */
1775 return (style
->wrap_text
||
1776 style
->v_align
== GNM_VALIGN_JUSTIFY
||
1777 style
->v_align
== GNM_VALIGN_DISTRIBUTED
||
1778 style
->h_align
== GNM_HALIGN_JUSTIFY
);
1782 gnm_style_set_shrink_to_fit (GnmStyle
*style
, gboolean f
)
1784 g_return_if_fail (style
!= NULL
);
1786 elem_changed (style
, MSTYLE_SHRINK_TO_FIT
);
1787 elem_set (style
, MSTYLE_SHRINK_TO_FIT
);
1788 style
->shrink_to_fit
= !!f
;
1792 gnm_style_get_shrink_to_fit (GnmStyle
const *style
)
1794 g_return_val_if_fail (style
!= NULL
, FALSE
);
1795 g_return_val_if_fail (elem_is_set (style
, MSTYLE_SHRINK_TO_FIT
), FALSE
);
1797 return style
->shrink_to_fit
;
1801 gnm_style_set_contents_locked (GnmStyle
*style
, gboolean f
)
1803 g_return_if_fail (style
!= NULL
);
1805 elem_changed (style
, MSTYLE_CONTENTS_LOCKED
);
1806 elem_set (style
, MSTYLE_CONTENTS_LOCKED
);
1807 style
->contents_locked
= !!f
;
1811 gnm_style_get_contents_locked (GnmStyle
const *style
)
1813 g_return_val_if_fail (style
!= NULL
, FALSE
);
1814 g_return_val_if_fail (elem_is_set (style
, MSTYLE_CONTENTS_LOCKED
), FALSE
);
1816 return style
->contents_locked
;
1820 gnm_style_set_contents_hidden (GnmStyle
*style
, gboolean f
)
1822 g_return_if_fail (style
!= NULL
);
1824 elem_changed (style
, MSTYLE_CONTENTS_HIDDEN
);
1825 elem_set (style
, MSTYLE_CONTENTS_HIDDEN
);
1826 style
->contents_hidden
= !!f
;
1830 gnm_style_get_contents_hidden (GnmStyle
const *style
)
1832 g_return_val_if_fail (style
!= NULL
, FALSE
);
1833 g_return_val_if_fail (elem_is_set (style
, MSTYLE_CONTENTS_HIDDEN
), FALSE
);
1835 return style
->contents_hidden
;
1839 * gnm_style_set_validation:
1841 * @v: (transfer full): #GnmValidation
1844 gnm_style_set_validation (GnmStyle
*style
, GnmValidation
*v
)
1846 g_return_if_fail (style
!= NULL
);
1848 elem_clear_contents (style
, MSTYLE_VALIDATION
);
1849 elem_changed (style
, MSTYLE_VALIDATION
);
1850 elem_set (style
, MSTYLE_VALIDATION
);
1851 style
->validation
= v
;
1855 * gnm_style_get_validation:
1858 * Returns: (transfer none):
1860 GnmValidation
const *
1861 gnm_style_get_validation (GnmStyle
const *style
)
1863 g_return_val_if_fail (style
!= NULL
, NULL
);
1864 g_return_val_if_fail (elem_is_set (style
, MSTYLE_VALIDATION
), NULL
);
1866 return style
->validation
;
1870 * gnm_style_set_hlink:
1872 * @lnk: (transfer full): #GnmHLink
1874 * This sets a link for @style.
1877 gnm_style_set_hlink (GnmStyle
*style
, GnmHLink
*lnk
)
1879 g_return_if_fail (style
!= NULL
);
1881 elem_clear_contents (style
, MSTYLE_HLINK
);
1882 elem_changed (style
, MSTYLE_HLINK
);
1883 elem_set (style
, MSTYLE_HLINK
);
1888 * gnm_style_get_hlink:
1891 * Returns: (transfer none): the associated #GnmHLink.
1894 gnm_style_get_hlink (GnmStyle
const *style
)
1896 g_return_val_if_fail (style
!= NULL
, NULL
);
1897 g_return_val_if_fail (elem_is_set (style
, MSTYLE_HLINK
), NULL
);
1899 return style
->hlink
;
1903 * gnm_style_set_input_msg:
1905 * @msg: (transfer full): #GnmInputMsg
1907 * This sets an input message for @style.
1910 gnm_style_set_input_msg (GnmStyle
*style
, GnmInputMsg
*msg
)
1912 g_return_if_fail (style
!= NULL
);
1914 elem_clear_contents (style
, MSTYLE_INPUT_MSG
);
1915 elem_changed (style
, MSTYLE_INPUT_MSG
);
1916 elem_set (style
, MSTYLE_INPUT_MSG
);
1917 style
->input_msg
= msg
;
1921 * gnm_style_get_input_msg:
1924 * Returns: (transfer none): the currently set input message assuming
1925 * that the style has such.
1928 gnm_style_get_input_msg (GnmStyle
const *style
)
1930 g_return_val_if_fail (style
!= NULL
, NULL
);
1931 g_return_val_if_fail (elem_is_set (style
, MSTYLE_INPUT_MSG
), NULL
);
1933 return style
->input_msg
;
1937 * gnm_style_set_conditions:
1939 * @sc: (transfer full): #GnmStyleConditions
1941 * This sets conditional style for @style.
1944 gnm_style_set_conditions (GnmStyle
*style
, GnmStyleConditions
*sc
)
1946 g_return_if_fail (style
!= NULL
);
1948 elem_clear_contents (style
, MSTYLE_CONDITIONS
);
1949 elem_changed (style
, MSTYLE_CONDITIONS
);
1950 elem_set (style
, MSTYLE_CONDITIONS
);
1951 style
->conditions
= sc
;
1955 * gnm_style_get_conditions:
1958 * Returns: (transfer none): the currently set conditional style assuming
1959 * that the style has such.
1961 GnmStyleConditions
*
1962 gnm_style_get_conditions (GnmStyle
const *style
)
1964 g_return_val_if_fail (style
!= NULL
, NULL
);
1965 g_return_val_if_fail (elem_is_set (style
, MSTYLE_CONDITIONS
), NULL
);
1966 return style
->conditions
;
1970 debug_style_deps (void)
1972 static int debug
= -1;
1974 debug
= gnm_debug_flag ("style-deps");
1979 * Just a simple version for now. We can also ignore most function
1980 * calls[1] and self-references[2].
1982 * [1] Excluding volatile (TODAY, ...) and those that can create references
1983 * outside the arguments (INDIRECT).
1985 * [2] References that print like A1 when used in A1.
1988 cond_expr_harmless (GnmExpr
const *expr
)
1990 GnmValue
const *v
= gnm_expr_get_constant (expr
);
1991 if (v
&& !VALUE_IS_CELLRANGE (v
))
1999 gnm_style_link_dependents (GnmStyle
*style
, GnmRange
const *r
)
2001 GnmStyleConditions
*sc
;
2004 g_return_if_fail (style
!= NULL
);
2005 g_return_if_fail (r
!= NULL
);
2007 sheet
= style
->linked_sheet
;
2010 * Conditional formatting.
2012 * We need to trigger a reformatting of the cell if a cell referenced
2013 * by the condition changes.
2015 sc
= elem_is_set (style
, MSTYLE_CONDITIONS
)
2016 ? gnm_style_get_conditions (style
)
2019 GPtrArray
const *conds
= gnm_style_conditions_details (sc
);
2021 if (debug_style_deps ())
2022 g_printerr ("Linking %s for %p\n",
2023 range_as_string (r
), style
);
2024 for (ui
= 0; conds
&& ui
< conds
->len
; ui
++) {
2025 GnmStyleCond
const *c
= g_ptr_array_index (conds
, ui
);
2028 for (ei
= 0; ei
< 2; ei
++) {
2029 GnmExprTop
const *texpr
=
2030 gnm_style_cond_get_expr (c
, ei
);
2032 cond_expr_harmless (texpr
->expr
))
2035 style
->deps
= g_ptr_array_new ();
2036 gnm_dep_style_dependency
2037 (sheet
, texpr
, r
, style
->deps
);
2045 * We can probably ignore those. If a dependent cell changes such
2046 * that a validation condition is no longer satisfied, it is
2047 * grandfathered in as valid.
2050 /* The style owns the deps. */
2054 gnm_style_unlink_dependents (GnmStyle
*style
, GnmRange
const *r
)
2058 g_return_if_fail (style
!= NULL
);
2059 g_return_if_fail (r
!= NULL
);
2064 for (ui
= k
= 0; ui
< style
->deps
->len
; ui
++) {
2065 GnmDependent
*dep
= g_ptr_array_index (style
->deps
, ui
);
2066 GnmCellPos
const *pos
= dependent_pos (dep
);
2068 if (range_contains (r
, pos
->col
, pos
->row
)) {
2069 if (debug_style_deps ())
2070 g_printerr ("Unlinking %s for %p\n",
2071 cellpos_as_string (pos
), style
);
2072 dependent_set_expr (dep
, NULL
);
2075 g_ptr_array_index (style
->deps
, k
) = dep
;
2080 g_ptr_array_set_size (style
->deps
, k
);
2085 * gnm_style_visible_in_blank:
2086 * @style: style to query
2088 * Returns: %TRUE if the style is visible, i.e., not transparent. Specifically
2089 * that means if it has a background or a visible border.
2092 gnm_style_visible_in_blank (GnmStyle
const *style
)
2096 g_return_val_if_fail (style
!= NULL
, FALSE
);
2098 if (elem_is_set (style
, MSTYLE_PATTERN
) &&
2099 gnm_style_get_pattern (style
) > 0)
2102 for (i
= MSTYLE_BORDER_TOP
; i
<= MSTYLE_BORDER_DIAGONAL
; ++i
)
2103 if (elem_is_set (style
, i
) &&
2104 gnm_style_border_visible_in_blank (gnm_style_get_border (style
, i
)))
2111 add_attr (PangoAttrList
*attrs
, PangoAttribute
*attr
)
2113 attr
->start_index
= 0;
2114 attr
->end_index
= G_MAXINT
;
2115 pango_attr_list_insert (attrs
, attr
);
2119 * gnm_style_get_pango_attrs :
2123 gnm_style_get_pango_attrs (GnmStyle
const *style
,
2124 PangoContext
*context
,
2129 GnmFont
*font
= gnm_style_get_font (style
, context
);
2131 if (style
->pango_attrs
) {
2132 if (zoom
== style
->pango_attrs_zoom
) {
2133 pango_attr_list_ref (style
->pango_attrs
);
2134 return style
->pango_attrs
;
2136 pango_attr_list_unref (((GnmStyle
*)style
)->pango_attrs
);
2139 ((GnmStyle
*)style
)->pango_attrs
= l
= pango_attr_list_new ();
2140 ((GnmStyle
*)style
)->pango_attrs_zoom
= zoom
;
2141 ((GnmStyle
*)style
)->pango_attrs_height
= -1;
2143 /* Foreground colour. */
2144 /* See http://bugzilla.gnome.org/show_bug.cgi?id=105322 */
2146 GnmColor
const *fore
= style
->color
.font
;
2147 add_attr (l
, go_color_to_pango (fore
->go_color
, TRUE
));
2150 /* Handle underlining. */
2151 ul
= gnm_style_get_font_uline (style
);
2152 if (ul
!= UNDERLINE_NONE
)
2154 pango_attr_underline_new (gnm_translate_underline_to_pango (ul
)));
2156 /* Handle strikethrough. */
2157 if (gnm_style_get_font_strike (style
))
2158 add_attr (l
, pango_attr_strikethrough_new (TRUE
));
2160 /* Handle script. */
2161 switch (gnm_style_get_font_script (style
)) {
2163 case GO_FONT_SCRIPT_STANDARD
:
2165 case GO_FONT_SCRIPT_SUB
:
2166 add_attr (l
, go_pango_attr_subscript_new (TRUE
));
2168 case GO_FONT_SCRIPT_SUPER
:
2169 add_attr (l
, go_pango_attr_superscript_new (TRUE
));
2173 add_attr (l
, pango_attr_font_desc_new (font
->go
.font
->desc
));
2176 add_attr (l
, pango_attr_scale_new (zoom
));
2178 pango_attr_list_ref (l
);
2183 gnm_style_generate_attrs_full (GnmStyle
const *style
)
2185 GnmColor
const *fore
= style
->color
.font
;
2186 PangoAttrList
*l
= pango_attr_list_new ();
2188 add_attr (l
, pango_attr_family_new (gnm_style_get_font_name (style
)));
2189 add_attr (l
, pango_attr_size_new (gnm_style_get_font_size (style
) * PANGO_SCALE
));
2190 add_attr (l
, pango_attr_style_new (gnm_style_get_font_italic (style
)
2191 ? PANGO_STYLE_ITALIC
: PANGO_STYLE_NORMAL
));
2192 add_attr (l
, pango_attr_weight_new (gnm_style_get_font_bold (style
)
2193 ? PANGO_WEIGHT_BOLD
: PANGO_WEIGHT_NORMAL
));
2194 add_attr (l
, go_color_to_pango (fore
->go_color
, TRUE
));
2195 add_attr (l
, pango_attr_strikethrough_new
2196 (gnm_style_get_font_strike (style
)));
2197 add_attr (l
, pango_attr_underline_new
2198 (gnm_translate_underline_to_pango
2199 (gnm_style_get_font_uline (style
))));
2204 gnm_style_get_pango_height (GnmStyle
const *style
,
2205 PangoContext
*context
,
2208 PangoAttrList
*attrs
= gnm_style_get_pango_attrs (style
, context
, zoom
);
2210 if (style
->pango_attrs_height
== -1) {
2212 PangoLayout
*layout
= pango_layout_new (context
);
2213 GOFormat
const *fmt
;
2214 gboolean requires_translation
= FALSE
;
2216 fmt
= gnm_style_get_format (style
);
2217 if (!go_format_is_general (fmt
)) {
2218 GOFormatDetails details
;
2219 go_format_get_details (fmt
, &details
, NULL
);
2220 if (details
.family
== GO_FORMAT_SCIENTIFIC
&&
2221 details
.use_markup
) {
2223 = go_pango_attr_superscript_new (TRUE
);
2224 /* We want to superscript the "-01" in the */
2225 /* string "+1.23456789E-01" */
2226 a
->start_index
= 12;
2228 pango_attr_list_insert (attrs
, a
);
2229 requires_translation
= TRUE
;
2232 pango_layout_set_attributes (layout
, attrs
);
2233 pango_layout_set_text (layout
, "+1.23456789E-01", -1);
2234 if (requires_translation
)
2235 go_pango_translate_layout (layout
);
2236 pango_layout_get_pixel_size (layout
, NULL
, &h
);
2237 g_object_unref (layout
);
2238 ((GnmStyle
*)style
)->pango_attrs_height
= h
;
2241 pango_attr_list_unref (attrs
);
2242 return style
->pango_attrs_height
;
2247 gnm_style_set_from_pango_attribute (GnmStyle
*style
, PangoAttribute
const *attr
)
2249 switch (attr
->klass
->type
) {
2250 case PANGO_ATTR_FAMILY
:
2251 gnm_style_set_font_name (style
, ((PangoAttrString
*)attr
)->value
);
2253 case PANGO_ATTR_SIZE
:
2254 gnm_style_set_font_size (style
,
2255 ((PangoAttrInt
*)attr
)->value
/ (double)PANGO_SCALE
);
2257 case PANGO_ATTR_STYLE
:
2258 gnm_style_set_font_italic (style
,
2259 ((PangoAttrInt
*)attr
)->value
== PANGO_STYLE_ITALIC
);
2261 case PANGO_ATTR_WEIGHT
:
2262 gnm_style_set_font_bold (style
,
2263 ((PangoAttrInt
*)attr
)->value
>= PANGO_WEIGHT_BOLD
);
2265 case PANGO_ATTR_FOREGROUND
:
2266 gnm_style_set_font_color (style
, gnm_color_new_pango (
2267 &((PangoAttrColor
*)attr
)->color
));
2269 case PANGO_ATTR_UNDERLINE
:
2270 gnm_style_set_font_uline
2271 (style
, gnm_translate_underline_from_pango
2272 (((PangoAttrInt
*)attr
)->value
));
2274 case PANGO_ATTR_STRIKETHROUGH
:
2275 gnm_style_set_font_strike (style
,
2276 ((PangoAttrInt
*)attr
)->value
!= 0);
2279 gboolean script_seen
= FALSE
, script_set
= FALSE
;
2280 if (attr
->klass
->type
== go_pango_attr_superscript_get_attr_type ()) {
2282 if (((GOPangoAttrSuperscript
*)attr
)->val
== 1) {
2284 gnm_style_set_font_script
2285 (style
, GO_FONT_SCRIPT_SUPER
);
2287 } else if (attr
->klass
->type
== go_pango_attr_subscript_get_attr_type ()) {
2289 if (((GOPangoAttrSubscript
*)attr
)->val
== 1) {
2291 gnm_style_set_font_script
2292 (style
, GO_FONT_SCRIPT_SUB
);
2295 if (script_seen
&& !script_set
)
2296 gnm_style_set_font_script
2297 (style
, GO_FONT_SCRIPT_STANDARD
);
2298 break; /* ignored */
2303 /* ------------------------------------------------------------------------- */
2306 gnm_style_dump_color (GnmColor
*color
, GnmStyleElement elem
)
2309 g_printerr ("\t%s: %x:%x:%x%s\n",
2310 gnm_style_element_name
[elem
],
2311 GO_COLOR_UINT_R (color
->go_color
),
2312 GO_COLOR_UINT_G (color
->go_color
),
2313 GO_COLOR_UINT_B (color
->go_color
),
2314 color
->is_auto
? " auto" : "");
2316 g_printerr ("\t%s: (NULL)\n", gnm_style_element_name
[elem
]);
2320 gnm_style_dump_border (GnmBorder
*border
, GnmStyleElement elem
)
2322 g_printerr ("\t%s: ", gnm_style_element_name
[elem
]);
2324 g_printerr ("%d\n", border
->line_type
);
2326 g_printerr ("blank\n");
2331 * @style: style to dump
2333 * This function dumps the given style's contents to stderr. This is meant
2334 * for debug purposes only and doesn't do a very good job for, for example,
2335 * conditional style settings.
2338 gnm_style_dump (GnmStyle
const *style
)
2342 g_printerr ("Style Refs %d\n", style
->ref_count
);
2343 if (elem_is_set (style
, MSTYLE_COLOR_BACK
))
2344 gnm_style_dump_color (style
->color
.back
, MSTYLE_COLOR_BACK
);
2345 if (elem_is_set (style
, MSTYLE_COLOR_PATTERN
))
2346 gnm_style_dump_color (style
->color
.pattern
, MSTYLE_COLOR_PATTERN
);
2348 for (i
= MSTYLE_BORDER_TOP
; i
<= MSTYLE_BORDER_DIAGONAL
; ++i
)
2349 if (elem_is_set (style
, i
))
2350 gnm_style_dump_border (style
->borders
[i
-MSTYLE_BORDER_TOP
], i
);
2352 if (elem_is_set (style
, MSTYLE_PATTERN
))
2353 g_printerr ("\tpattern %d\n", style
->pattern
);
2354 if (elem_is_set (style
, MSTYLE_FONT_COLOR
))
2355 gnm_style_dump_color (style
->color
.font
, MSTYLE_FONT_COLOR
);
2356 if (elem_is_set (style
, MSTYLE_FONT_NAME
))
2357 g_printerr ("\tname '%s'\n", style
->font_detail
.name
->str
);
2358 if (elem_is_set (style
, MSTYLE_FONT_BOLD
))
2359 g_printerr (style
->font_detail
.bold
? "\tbold\n" : "\tnot bold\n");
2360 if (elem_is_set (style
, MSTYLE_FONT_ITALIC
))
2361 g_printerr (style
->font_detail
.italic
? "\titalic\n" : "\tnot italic\n");
2362 if (elem_is_set (style
, MSTYLE_FONT_UNDERLINE
))
2363 switch (style
->font_detail
.underline
) {
2365 case UNDERLINE_NONE
:
2366 g_printerr ("\tno underline\n"); break;
2367 case UNDERLINE_SINGLE
:
2368 g_printerr ("\tsingle underline\n"); break;
2369 case UNDERLINE_DOUBLE
:
2370 g_printerr ("\tdouble underline\n"); break;
2372 if (elem_is_set (style
, MSTYLE_FONT_STRIKETHROUGH
))
2373 g_printerr (style
->font_detail
.strikethrough
? "\tstrikethrough\n" : "\tno strikethrough\n");
2374 if (elem_is_set (style
, MSTYLE_FONT_SCRIPT
))
2375 switch (style
->font_detail
.script
) {
2376 case GO_FONT_SCRIPT_SUB
:
2377 g_printerr ("\tsubscript\n"); break;
2379 case GO_FONT_SCRIPT_STANDARD
:
2380 g_printerr ("\tno super or sub\n"); break;
2381 case GO_FONT_SCRIPT_SUPER
:
2382 g_printerr ("\tsuperscript\n"); break;
2384 if (elem_is_set (style
, MSTYLE_FONT_SIZE
))
2385 g_printerr ("\tsize %f\n", style
->font_detail
.size
);
2386 if (elem_is_set (style
, MSTYLE_FORMAT
)) {
2387 const char *fmt
= go_format_as_XL (style
->format
);
2388 g_printerr ("\tformat '%s'\n", fmt
);
2390 if (elem_is_set (style
, MSTYLE_ALIGN_V
))
2391 g_printerr ("\tvalign %hd\n", (short)style
->v_align
);
2392 if (elem_is_set (style
, MSTYLE_ALIGN_H
))
2393 g_printerr ("\thalign %hd\n", (short)style
->h_align
);
2394 if (elem_is_set (style
, MSTYLE_INDENT
))
2395 g_printerr ("\tindent %d\n", style
->indent
);
2396 if (elem_is_set (style
, MSTYLE_ROTATION
))
2397 g_printerr ("\trotation %d\n", style
->rotation
);
2398 if (elem_is_set (style
, MSTYLE_TEXT_DIR
))
2399 g_printerr ("\ttext dir %d\n", style
->text_dir
);
2400 if (elem_is_set (style
, MSTYLE_WRAP_TEXT
))
2401 g_printerr ("\twrap text %d\n", style
->wrap_text
);
2402 if (elem_is_set (style
, MSTYLE_SHRINK_TO_FIT
))
2403 g_printerr ("\tshrink to fit %d\n", style
->shrink_to_fit
);
2404 if (elem_is_set (style
, MSTYLE_CONTENTS_LOCKED
))
2405 g_printerr ("\tlocked %d\n", style
->contents_locked
);
2406 if (elem_is_set (style
, MSTYLE_CONTENTS_HIDDEN
))
2407 g_printerr ("\thidden %d\n", style
->contents_hidden
);
2408 if (elem_is_set (style
, MSTYLE_VALIDATION
))
2409 g_printerr ("\tvalidation %p\n", (void *)style
->validation
);
2410 if (elem_is_set (style
, MSTYLE_HLINK
))
2411 g_printerr ("\thlink %p\n", (void *)style
->hlink
);
2412 if (elem_is_set (style
, MSTYLE_INPUT_MSG
))
2413 g_printerr ("\tinput msg %p\n", (void *)style
->input_msg
);
2414 if (elem_is_set (style
, MSTYLE_CONDITIONS
))
2415 g_printerr ("\tconditions %p\n", (void *)style
->conditions
);
2418 /* ------------------------------------------------------------------------- */
2421 gnm_style_init (void)
2425 go_mem_chunk_new ("style pool",
2433 cb_gnm_style_pool_leak (gpointer data
, G_GNUC_UNUSED gpointer user
)
2435 GnmStyle
*style
= data
;
2436 g_printerr ("Leaking style at %p.\n", (void *)style
);
2437 gnm_style_dump (style
);
2442 gnm_style_shutdown (void)
2445 go_mem_chunk_foreach_leak (gnm_style_pool
, cb_gnm_style_pool_leak
, NULL
);
2446 go_mem_chunk_destroy (gnm_style_pool
, FALSE
);
2447 gnm_style_pool
= NULL
;