2 * mstyle.c: Storing a style
5 * Michael Meeks <mmeeks@gnu.org>
6 * Almer S. Tigelaar <almer@gnome.org>
7 * Jody Goldberg <jody@gnome.org>
8 * Morten Welinder <terra@gnome.org>
10 #include <gnumeric-config.h>
14 #include "sheet-style.h"
15 #include "style-border.h"
16 #include "style-font.h"
17 #include "style-color.h"
18 #include "style-conditions.h"
19 #include "validation.h"
22 #include "input-msg.h"
23 #include "application.h"
24 #include "parse-util.h"
29 #include "gnumeric-conf.h"
30 #include <goffice/goffice.h>
34 #ifndef USE_MSTYLE_POOL
35 #define USE_MSTYLE_POOL 1
39 /* Memory pool for GnmStyles. */
40 static GOMemChunk
*gnm_style_pool
;
41 #define CHUNK_ALLOC(T,p) ((T*)go_mem_chunk_alloc (p))
42 #define CHUNK_ALLOC0(T,p) ((T*)go_mem_chunk_alloc0 (p))
43 #define CHUNK_FREE(p,v) go_mem_chunk_free ((p), (v))
45 #define CHUNK_ALLOC(T,c) g_new (T,1)
46 #define CHUNK_ALLOC0(T,c) g_new0 (T,1)
47 #define CHUNK_FREE(p,v) g_free ((v))
55 unsigned int hash_key
;
56 unsigned int hash_key_xl
;
57 unsigned int ref_count
;
58 unsigned int link_count
;
61 PangoAttrList
*pango_attrs
;
62 double pango_attrs_zoom
;
63 int pango_attrs_height
;
66 PangoContext
*font_context
;
69 struct _GnmStyleColor
{
74 GnmBorder
*borders
[MSTYLE_BORDER_DIAGONAL
- MSTYLE_BORDER_TOP
+ 1];
77 /* FIXME: TODO use GOFont */
78 struct _GnmStyleFontDetails
{
82 GnmUnderline underline
;
83 gboolean strikethrough
;
88 GOFormat
const *format
;
95 gboolean shrink_to_fit
;
96 gboolean contents_locked
;
97 gboolean contents_hidden
;
99 GnmValidation
*validation
;
101 GnmInputMsg
*input_msg
;
102 GnmStyleConditions
*conditions
;
103 GPtrArray
*cond_styles
;
108 #define elem_changed(style, elem) do { (style)->changed |= (1u << (elem)); } while(0)
109 #define elem_set(style, elem) do { (style)->set |= (1u << (elem)); } while(0)
110 #define elem_unset(style, elem) do { (style)->set &= ~(1u << (elem)); } while(0)
111 #define elem_is_set(style, elem) (((style)->set & (1u << (elem))) != 0)
113 #define MSTYLE_ANY_BORDER MSTYLE_BORDER_TOP: \
114 case MSTYLE_BORDER_BOTTOM: \
115 case MSTYLE_BORDER_LEFT: \
116 case MSTYLE_BORDER_RIGHT: \
117 case MSTYLE_BORDER_DIAGONAL: \
118 case MSTYLE_BORDER_REV_DIAGONAL
121 #define UNROLLED_FOR(init_,cond_,step_,code_) \
124 if (cond_) { code_; step_; \
125 if (cond_) { code_; step_; \
126 if (cond_) { code_; step_; \
127 if (cond_) { code_; step_; \
128 if (cond_) { code_; step_; \
129 if (cond_) { code_; step_; \
130 if (cond_) { code_; step_; \
131 if (cond_) { code_; step_; \
132 if (cond_) { code_; step_; \
133 if (cond_) { code_; step_; \
134 if (cond_) { code_; step_; \
135 if (cond_) { code_; step_; \
136 if (cond_) { code_; step_; \
137 if (cond_) { code_; step_; \
138 if (cond_) { code_; step_; \
139 if (cond_) { code_; step_; \
140 if (cond_) { code_; step_; \
141 if (cond_) { code_; step_; \
142 if (cond_) { code_; step_; \
143 if (cond_) { code_; step_; \
144 if (cond_) { code_; step_; \
145 if (cond_) { code_; step_; \
146 if (cond_) { code_; step_; \
147 if (cond_) { code_; step_; \
148 if (cond_) { code_; step_; \
149 if (cond_) { code_; step_; \
150 if (cond_) { code_; step_; \
151 if (cond_) { code_; step_; \
152 if (cond_) { code_; step_; \
153 if (cond_) { code_; step_; \
154 if (cond_) { code_; step_; \
155 if (cond_) { code_; step_; \
156 if (cond_) { code_; step_; \
157 if (cond_) { code_; step_; \
158 if (cond_) { code_; step_; \
159 if (cond_) { code_; step_; \
160 if (cond_) { code_; step_; \
161 if (cond_) { code_; step_; \
162 if (cond_) { code_; step_; \
163 if (cond_) { code_; step_; \
164 if (cond_) { code_; step_; \
165 if (cond_) { code_; step_; \
166 if (cond_) { code_; step_; \
167 if (cond_) { code_; step_; \
168 if (cond_) { code_; step_; \
169 if (cond_) { code_; step_; \
170 if (cond_) { code_; step_; \
171 if (cond_) { code_; step_; \
172 if (cond_) { code_; step_; \
173 if (cond_) { code_; step_; \
174 g_assert_not_reached (); \
175 }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} \
180 static char const * const
181 gnm_style_element_name
[MSTYLE_ELEMENT_MAX
] = {
188 "Border.RevDiagonal",
196 "Font.Strikethrough",
213 /* Some ref/link count debugging */
215 #define d(arg) g_printerr arg
217 #define d(arg) do { } while (0)
221 clear_conditional_merges (GnmStyle
*style
)
223 if (style
->cond_styles
) {
224 unsigned i
= style
->cond_styles
->len
;
226 gnm_style_unref (g_ptr_array_index (style
->cond_styles
, i
));
227 g_ptr_array_free (style
->cond_styles
, TRUE
);
228 style
->cond_styles
= NULL
;
232 #define MIX(H) do { \
233 H *= G_GUINT64_CONSTANT(123456789012345); \
238 gnm_style_update (GnmStyle
*style
)
243 g_return_if_fail (style
->changed
);
247 clear_conditional_merges (style
);
248 if (elem_is_set (style
, MSTYLE_CONDITIONS
) && style
->conditions
)
249 style
->cond_styles
= gnm_style_conditions_overlay (style
->conditions
, style
);
251 /* ---------------------------------------- */
253 if (elem_is_set (style
, MSTYLE_COLOR_BACK
)) {
254 if (!style
->color
.back
->is_auto
)
255 hash
^= GPOINTER_TO_UINT (style
->color
.back
);
261 if (elem_is_set (style
, MSTYLE_COLOR_PATTERN
)) {
262 if (!style
->color
.pattern
->is_auto
)
263 hash
^= GPOINTER_TO_UINT (style
->color
.pattern
);
269 if (elem_is_set (style
, MSTYLE_FONT_COLOR
)) {
270 if (!style
->color
.font
->is_auto
)
271 hash
^= GPOINTER_TO_UINT (style
->color
.font
);
277 for (i
= MSTYLE_BORDER_TOP
; i
<= MSTYLE_BORDER_DIAGONAL
; i
++) {
278 if (elem_is_set (style
, i
))
279 hash
^= GPOINTER_TO_UINT (style
->borders
[i
- MSTYLE_BORDER_TOP
]);
285 if (elem_is_set (style
, MSTYLE_PATTERN
))
286 hash
^= style
->pattern
;
289 if (elem_is_set (style
, MSTYLE_FONT_NAME
))
290 hash
^= GPOINTER_TO_UINT (style
->font_detail
.name
);
293 if (elem_is_set (style
, MSTYLE_FONT_BOLD
))
294 hash
^= (style
->font_detail
.bold
? 1 : 2);
297 if (elem_is_set (style
, MSTYLE_FONT_ITALIC
))
298 hash
^= (style
->font_detail
.italic
? 1 : 2);
301 if (elem_is_set (style
, MSTYLE_FONT_UNDERLINE
))
302 hash
^= (style
->font_detail
.underline
? 1 : 2);
305 if (elem_is_set (style
, MSTYLE_FONT_STRIKETHROUGH
))
306 hash
^= (style
->font_detail
.strikethrough
? 1 : 2);
309 if (elem_is_set (style
, MSTYLE_FONT_SCRIPT
))
310 hash
^= (style
->font_detail
.script
+ 0x100);
313 if (elem_is_set (style
, MSTYLE_FONT_SIZE
))
314 hash
^= ((int)(style
->font_detail
.size
* 97));
317 if (elem_is_set (style
, MSTYLE_FORMAT
))
318 hash
^= GPOINTER_TO_UINT (style
->format
);
321 if (elem_is_set (style
, MSTYLE_ALIGN_H
))
322 hash
^= (style
->h_align
+ 0x100);
325 if (elem_is_set (style
, MSTYLE_ALIGN_V
))
326 hash
^= (style
->v_align
+ 0x100);
329 if (elem_is_set (style
, MSTYLE_INDENT
))
330 hash
^= style
->indent
;
333 if (elem_is_set (style
, MSTYLE_ROTATION
))
334 hash
^= style
->rotation
;
337 if (elem_is_set (style
, MSTYLE_TEXT_DIR
))
338 hash
^= (style
->text_dir
+ 0x100);
341 if (elem_is_set (style
, MSTYLE_WRAP_TEXT
))
342 hash
^= (style
->wrap_text
? 1 : 2);
345 if (elem_is_set (style
, MSTYLE_SHRINK_TO_FIT
))
346 hash
^= (style
->shrink_to_fit
? 1 : 2);
349 if (elem_is_set (style
, MSTYLE_CONTENTS_LOCKED
))
350 hash
^= (style
->contents_locked
? 1 : 2);
353 if (elem_is_set (style
, MSTYLE_CONTENTS_HIDDEN
))
354 hash
^= (style
->contents_hidden
? 1 : 2);
357 style
->hash_key_xl
= (guint32
)hash
;
359 /* From here on, fields are not in MS XL */
361 if (elem_is_set (style
, MSTYLE_VALIDATION
)) {
363 * The hash used must not depend on the expressions inside
366 hash
^= (style
->validation
!= NULL
? 1 : 2);
370 if (elem_is_set (style
, MSTYLE_HLINK
))
371 hash
^= GPOINTER_TO_UINT (style
->hlink
);
374 if (elem_is_set (style
, MSTYLE_INPUT_MSG
))
375 hash
^= GPOINTER_TO_UINT (style
->input_msg
);
378 if (elem_is_set (style
, MSTYLE_CONDITIONS
)) {
380 * The hash used must not depend on the expressions inside
383 hash
^= style
->conditions
384 ? gnm_style_conditions_hash (style
->conditions
)
389 style
->hash_key
= (guint32
)hash
;
391 if (G_UNLIKELY (style
->set
== 0)) {
393 * gnm_style_new and gnm_style_dup both assume that the
394 * correct hash values (both of them) for the empty style
397 g_assert (style
->hash_key
== 0);
398 g_assert (style
->hash_key_xl
== 0);
405 gnm_style_hash_XL (gconstpointer style
)
407 if (((GnmStyle
const *)style
)->changed
)
408 gnm_style_update ((GnmStyle
*)style
);
409 return ((GnmStyle
const *)style
)->hash_key_xl
;
413 gnm_style_hash (gconstpointer style
)
415 if (((GnmStyle
const *)style
)->changed
)
416 gnm_style_update ((GnmStyle
*)style
);
417 return ((GnmStyle
const *)style
)->hash_key
;
420 #define ELEM_IS_EQ(a,b,elem) \
421 (elem == MSTYLE_COLOR_BACK \
422 ? a->color.back == b->color.back || (a->color.back->is_auto && b->color.back->is_auto) \
423 : (elem == MSTYLE_COLOR_PATTERN \
424 ? a->color.pattern == b->color.pattern || (a->color.pattern->is_auto && b->color.pattern->is_auto) \
425 : (elem >= MSTYLE_BORDER_TOP && elem <= MSTYLE_BORDER_DIAGONAL) \
426 ? a->borders[elem - MSTYLE_BORDER_TOP] == b->borders[elem - MSTYLE_BORDER_TOP] \
427 : (elem == MSTYLE_PATTERN \
428 ? a->pattern == b->pattern \
429 : (elem == MSTYLE_FONT_COLOR \
430 ? a->color.font == b->color.font || (a->color.font->is_auto && b->color.font->is_auto) \
431 : (elem == MSTYLE_FONT_NAME \
432 ? a->font_detail.name == b->font_detail.name \
433 : (elem == MSTYLE_FONT_BOLD \
434 ? a->font_detail.bold == b->font_detail.bold \
435 : (elem == MSTYLE_FONT_ITALIC \
436 ? a->font_detail.italic == b->font_detail.italic \
437 : (elem == MSTYLE_FONT_UNDERLINE \
438 ? a->font_detail.underline == b->font_detail.underline \
439 : (elem == MSTYLE_FONT_STRIKETHROUGH \
440 ? a->font_detail.strikethrough == b->font_detail.strikethrough \
441 : (elem == MSTYLE_FONT_SCRIPT \
442 ? a->font_detail.script == b->font_detail.script \
443 : (elem == MSTYLE_FONT_SIZE \
444 ? a->font_detail.size == b->font_detail.size \
445 : (elem == MSTYLE_FORMAT \
446 ? a->format == b->format \
447 : (elem == MSTYLE_ALIGN_V \
448 ? a->v_align == b->v_align \
449 : (elem == MSTYLE_ALIGN_H \
450 ? a->h_align == b->h_align \
451 : (elem == MSTYLE_INDENT \
452 ? a->indent == b->indent \
453 : (elem == MSTYLE_ROTATION \
454 ? a->rotation == b->rotation \
455 : (elem == MSTYLE_TEXT_DIR \
456 ? a->text_dir == b->text_dir \
457 : (elem == MSTYLE_WRAP_TEXT \
458 ? a->wrap_text == b->wrap_text \
459 : (elem == MSTYLE_SHRINK_TO_FIT \
460 ? a->shrink_to_fit == b->shrink_to_fit \
461 : (elem == MSTYLE_CONTENTS_LOCKED \
462 ? a->contents_locked == b->contents_locked \
463 : (elem == MSTYLE_CONTENTS_HIDDEN \
464 ? a->contents_hidden == b->contents_hidden \
465 : (elem == MSTYLE_VALIDATION \
466 ? a->validation == b->validation \
467 : (elem == MSTYLE_HLINK \
468 ? a->hlink == b->hlink \
469 : (elem == MSTYLE_INPUT_MSG \
470 ? a->input_msg == b->input_msg \
471 : (elem == MSTYLE_CONDITIONS \
472 ? (a->conditions == b->conditions || \
473 (a->conditions && b->conditions && \
474 gnm_style_conditions_equal (a->conditions, b->conditions, FALSE))) \
475 : FALSE)))))))))))))))))))))))))
478 * Note: the above is suboptimal for validation, hlink, input_msg.
480 * We are comparing pointers (which at least safely matches what we do
481 * with the hash), but I think we want proper equality.
485 elem_is_eq (GnmStyle
const *a
, GnmStyle
const *b
, GnmStyleElement elem
)
487 return ELEM_IS_EQ (a
, b
, elem
);
491 elem_assign_contents (GnmStyle
*dst
, GnmStyle
const *src
, GnmStyleElement elem
)
494 g_return_if_fail (src
!= dst
);
495 g_return_if_fail (elem_is_set (src
, elem
));
498 case MSTYLE_COLOR_BACK
: style_color_ref (dst
->color
.back
= src
->color
.back
); return;
499 case MSTYLE_COLOR_PATTERN
: style_color_ref (dst
->color
.pattern
= src
->color
.pattern
); return;
500 case MSTYLE_ANY_BORDER
:
501 elem
-= MSTYLE_BORDER_TOP
;
502 gnm_style_border_ref (dst
->borders
[elem
] = src
->borders
[elem
]);
504 case MSTYLE_PATTERN
: dst
->pattern
= src
->pattern
; return;
505 case MSTYLE_FONT_COLOR
: style_color_ref (dst
->color
.font
= src
->color
.font
); return;
506 case MSTYLE_FONT_NAME
: go_string_ref (dst
->font_detail
.name
= src
->font_detail
.name
); return;
507 case MSTYLE_FONT_BOLD
: dst
->font_detail
.bold
= src
->font_detail
.bold
; return;
508 case MSTYLE_FONT_ITALIC
: dst
->font_detail
.italic
= src
->font_detail
.italic
; return;
509 case MSTYLE_FONT_UNDERLINE
: dst
->font_detail
.underline
= src
->font_detail
.underline
; return;
510 case MSTYLE_FONT_STRIKETHROUGH
: dst
->font_detail
.strikethrough
= src
->font_detail
.strikethrough
; return;
511 case MSTYLE_FONT_SCRIPT
: dst
->font_detail
.script
= src
->font_detail
.script
; return;
512 case MSTYLE_FONT_SIZE
: dst
->font_detail
.size
= src
->font_detail
.size
; return;
513 case MSTYLE_FORMAT
: go_format_ref (dst
->format
= src
->format
); return;
514 case MSTYLE_ALIGN_V
: dst
->v_align
= src
->v_align
; return;
515 case MSTYLE_ALIGN_H
: dst
->h_align
= src
->h_align
; return;
516 case MSTYLE_INDENT
: dst
->indent
= src
->indent
; return;
517 case MSTYLE_ROTATION
: dst
->rotation
= src
->rotation
; return;
518 case MSTYLE_TEXT_DIR
: dst
->text_dir
= src
->text_dir
; return;
519 case MSTYLE_WRAP_TEXT
: dst
->wrap_text
= src
->wrap_text
; return;
520 case MSTYLE_SHRINK_TO_FIT
: dst
->shrink_to_fit
= src
->shrink_to_fit
; return;
521 case MSTYLE_CONTENTS_LOCKED
: dst
->contents_locked
= src
->contents_locked
; return;
522 case MSTYLE_CONTENTS_HIDDEN
: dst
->contents_hidden
= src
->contents_hidden
; return;
523 case MSTYLE_VALIDATION
:
524 if ((dst
->validation
= src
->validation
))
525 gnm_validation_ref (dst
->validation
);
528 if ((dst
->hlink
= src
->hlink
))
529 g_object_ref (dst
->hlink
);
531 case MSTYLE_INPUT_MSG
:
532 if ((dst
->input_msg
= src
->input_msg
))
533 g_object_ref (dst
->input_msg
);
535 case MSTYLE_CONDITIONS
:
536 if ((dst
->conditions
= src
->conditions
))
537 g_object_ref (dst
->conditions
);
545 elem_clear_contents (GnmStyle
*style
, GnmStyleElement elem
)
548 g_return_if_fail (style
!= NULL
);
550 if (!elem_is_set (style
, elem
))
554 case MSTYLE_COLOR_BACK
: style_color_unref (style
->color
.back
); return;
555 case MSTYLE_COLOR_PATTERN
: style_color_unref (style
->color
.pattern
); return;
556 case MSTYLE_ANY_BORDER
:
557 gnm_style_border_unref (style
->borders
[elem
- MSTYLE_BORDER_TOP
]);
559 case MSTYLE_FONT_COLOR
: style_color_unref (style
->color
.font
); return;
560 case MSTYLE_FONT_NAME
: go_string_unref (style
->font_detail
.name
); return;
561 case MSTYLE_FORMAT
: go_format_unref (style
->format
); return;
562 case MSTYLE_VALIDATION
:
563 if (style
->validation
)
564 gnm_validation_unref (style
->validation
);
568 g_object_unref (style
->hlink
);
570 case MSTYLE_INPUT_MSG
:
571 if (style
->input_msg
)
572 g_object_unref (style
->input_msg
);
574 case MSTYLE_CONDITIONS
:
575 if (style
->conditions
) {
576 clear_conditional_merges (style
);
577 g_object_unref (style
->conditions
);
586 * gnm_style_find_conflicts :
587 * @accum: accumulator #GnmStyle
588 * @overlay: #GnmStyle
591 * Copy any items from @overlay that do not conflict with the values in @accum.
592 * If an element had a previous conflict (flagged via @conflicts) it is ignored.
594 * Returns @conflicts with any new conflicts added.
597 gnm_style_find_conflicts (GnmStyle
*accum
, GnmStyle
const *overlay
,
598 unsigned int conflicts
)
602 g_assert (MSTYLE_ELEMENT_MAX
<= CHAR_BIT
* sizeof (conflicts
));
604 for (i
= 0; i
< MSTYLE_ELEMENT_MAX
; i
++) {
605 if (conflicts
& (1u << i
) || !elem_is_set (overlay
, i
)) {
607 } else if (!elem_is_set (accum
, i
)) {
608 elem_assign_contents (accum
, overlay
, i
);
610 elem_changed (accum
, i
);
611 } else if (!elem_is_eq (accum
, overlay
, i
))
612 conflicts
|= (1u << i
);
618 #define GNM_INPUT_MSG_EQUAL3(a,b,r) (gnm_input_msg_equal (a,b))
620 #define RELAX_CHECK(op_,field_,checker_) do { \
621 if (diffs & (1u << (op_)) && \
622 elem_is_set (a, (op_)) && \
623 elem_is_set (b, (op_)) && \
624 ((a->field_ == NULL) != (b->field_ == NULL) || \
625 checker_ (a->field_, b->field_, relax_sheet))) \
626 diffs &= ~(1u << (op_)); \
630 * gnm_style_find_differences:
633 * @relax_sheet: if %TRUE, ignore differences solely caused by being linked into different sheets.
635 * Determine how two fully-qualified styles differ.
637 * Returns differences as a bitset of #GnmStyleElement.
640 gnm_style_find_differences (GnmStyle
const *a
, GnmStyle
const *b
,
641 gboolean relax_sheet
)
644 unsigned int diffs
= 0;
646 g_assert (MSTYLE_ELEMENT_MAX
<= CHAR_BIT
* sizeof (diffs
));
648 for (i
= 0; i
< MSTYLE_ELEMENT_MAX
; i
++) {
649 if (elem_is_set (a
, i
) != elem_is_set (b
, i
) ||
650 (elem_is_set (a
, i
) && !elem_is_eq (a
, b
, i
)))
655 RELAX_CHECK (MSTYLE_HLINK
, hlink
, gnm_hlink_equal
);
656 RELAX_CHECK (MSTYLE_VALIDATION
, validation
, gnm_validation_equal
);
657 RELAX_CHECK (MSTYLE_INPUT_MSG
, input_msg
, GNM_INPUT_MSG_EQUAL3
);
658 RELAX_CHECK (MSTYLE_CONDITIONS
, conditions
, gnm_style_conditions_equal
);
665 #undef GNM_INPUT_MSG_EQUAL3
668 gnm_style_clear_pango (GnmStyle
*style
)
670 if (style
->pango_attrs
) {
671 pango_attr_list_unref (style
->pango_attrs
);
672 style
->pango_attrs
= NULL
;
678 gnm_style_clear_font (GnmStyle
*style
)
681 gnm_font_unref (style
->font
);
684 g_clear_object (&style
->font_context
);
690 * Returns: (transfer full): a new style with _no_ elements set.
695 GnmStyle
*style
= CHUNK_ALLOC0 (GnmStyle
, gnm_style_pool
);
697 style
->ref_count
= 1;
698 style
->link_count
= 0;
699 style
->linked_sheet
= NULL
;
700 style
->pango_attrs
= NULL
;
702 style
->validation
= NULL
;
704 style
->set
= style
->changed
= 0;
705 style
->validation
= NULL
;
707 style
->input_msg
= NULL
;
708 style
->conditions
= NULL
;
710 d(("new %p\n", style
));
716 * gnm_style_new_default:
718 * Returns: (transfer full): a new style initialized to the default state.
721 gnm_style_new_default (void)
723 GnmStyle
*new_style
= gnm_style_new ();
726 gnm_style_set_font_name (new_style
, gnm_conf_get_core_defaultfont_name ());
727 gnm_style_set_font_size (new_style
, gnm_conf_get_core_defaultfont_size ());
728 gnm_style_set_font_bold (new_style
, gnm_conf_get_core_defaultfont_bold ());
729 gnm_style_set_font_italic (new_style
, gnm_conf_get_core_defaultfont_italic ());
731 gnm_style_set_format (new_style
, go_format_general ());
732 gnm_style_set_align_v (new_style
, GNM_VALIGN_BOTTOM
);
733 gnm_style_set_align_h (new_style
, GNM_HALIGN_GENERAL
);
734 gnm_style_set_indent (new_style
, 0);
735 gnm_style_set_rotation (new_style
, 0);
736 gnm_style_set_text_dir (new_style
, GNM_TEXT_DIR_CONTEXT
);
737 gnm_style_set_wrap_text (new_style
, FALSE
);
738 gnm_style_set_shrink_to_fit (new_style
, FALSE
);
739 gnm_style_set_contents_locked (new_style
, TRUE
);
740 gnm_style_set_contents_hidden (new_style
, FALSE
);
741 gnm_style_set_font_uline (new_style
, UNDERLINE_NONE
);
742 gnm_style_set_font_strike (new_style
, FALSE
);
743 gnm_style_set_font_script (new_style
, GO_FONT_SCRIPT_STANDARD
);
745 gnm_style_set_validation (new_style
, NULL
);
746 gnm_style_set_hlink (new_style
, NULL
);
747 gnm_style_set_input_msg (new_style
, NULL
);
748 gnm_style_set_conditions (new_style
, NULL
);
750 gnm_style_set_font_color (new_style
, style_color_black ());
751 gnm_style_set_back_color (new_style
, style_color_auto_back ());
752 gnm_style_set_pattern_color (new_style
, style_color_black ());
754 for (i
= MSTYLE_BORDER_TOP
; i
<= MSTYLE_BORDER_DIAGONAL
; ++i
)
755 gnm_style_set_border (new_style
, i
,
756 gnm_style_border_ref (gnm_style_border_none ()));
757 gnm_style_set_pattern (new_style
, 0);
763 gnm_style_dup (GnmStyle
const *src
)
765 GnmStyle
*new_style
= CHUNK_ALLOC0 (GnmStyle
, gnm_style_pool
);
768 new_style
->ref_count
= 1;
769 for (i
= 0; i
< MSTYLE_ELEMENT_MAX
; i
++)
770 if (elem_is_set (src
, i
)) {
771 elem_assign_contents (new_style
, src
, i
);
772 elem_set (new_style
, i
);
773 elem_changed (new_style
, i
);
776 if ((new_style
->pango_attrs
= src
->pango_attrs
)) {
777 pango_attr_list_ref (new_style
->pango_attrs
);
778 new_style
->pango_attrs_zoom
= src
->pango_attrs_zoom
;
781 if ((new_style
->font
= src
->font
)) {
782 gnm_font_ref (new_style
->font
);
783 new_style
->font_context
= g_object_ref (src
->font_context
);
786 d(("dup %p\n", new_style
));
791 * gnm_style_new_merged :
793 * @overlay: #GnmStyle
795 * A new GnmStyle that contains any elements of @overlay that are set, and uses
796 * @base for anything that is not set in @overlay.
798 * Returns: (transfer full): A ref to a new GnmStyle.
801 gnm_style_new_merged (GnmStyle
const *base
, GnmStyle
const *overlay
)
803 GnmStyle
*new_style
= CHUNK_ALLOC0 (GnmStyle
, gnm_style_pool
);
806 new_style
->ref_count
= 1;
807 for (i
= 0; i
< MSTYLE_ELEMENT_MAX
; i
++) {
808 if (elem_is_set (overlay
, i
))
809 elem_assign_contents (new_style
, overlay
, i
);
810 else if (elem_is_set (base
, i
))
811 elem_assign_contents (new_style
, base
, i
);
814 elem_set (new_style
, i
);
815 elem_changed (new_style
, i
);
817 d(("copy merge %p\n", new_style
));
822 * gnm_style_ref: (skip)
825 * Returns: (transfer full): A new reference to @style.
828 gnm_style_ref (GnmStyle
const *style
)
830 g_return_val_if_fail (style
!= NULL
, NULL
);
831 g_return_val_if_fail (style
->ref_count
> 0, NULL
);
833 ((GnmStyle
*)style
)->ref_count
++;
834 d(("ref %p = %d\n", style
, style
->ref_count
));
836 return ((GnmStyle
*)style
);
840 * gnm_style_unref: (skip)
841 * @style: #GnmStyle const
843 * Unrefs and _potentially frees_ @style.
844 * Takes a _const_ pointer to facilitate life cycles. The const indicates that
845 * the content can not be changed, mainly when handling styles that are in the
849 gnm_style_unref (GnmStyle
const *style
)
851 g_return_if_fail (style
!= NULL
);
852 g_return_if_fail (style
->ref_count
> 0);
854 d(("unref %p = %d\n", style
, style
->ref_count
-1));
855 if (((GnmStyle
*)style
)->ref_count
-- <= 1) {
856 GnmStyle
*unconst
= (GnmStyle
*)style
;
859 g_return_if_fail (style
->link_count
== 0);
860 g_return_if_fail (style
->linked_sheet
== NULL
);
862 for (i
= 0; i
< MSTYLE_ELEMENT_MAX
; i
++)
863 elem_clear_contents (unconst
, i
);
865 clear_conditional_merges (unconst
);
866 gnm_style_clear_pango (unconst
);
867 gnm_style_clear_font (unconst
);
870 if (style
->deps
->len
> 0)
871 g_warning ("Leftover style deps!");
872 g_ptr_array_free (style
->deps
, TRUE
);
875 CHUNK_FREE (gnm_style_pool
, unconst
);
880 gnm_style_get_type (void)
885 t
= g_boxed_type_register_static ("GnmStyle",
886 (GBoxedCopyFunc
)gnm_style_ref
,
887 (GBoxedFreeFunc
)gnm_style_unref
);
893 * Replace auto pattern color in style with sheet's auto pattern color.
894 * make_copy tells if we are allowed to modify the style in place or we must
898 link_pattern_color (GnmStyle
*style
, GnmColor
*auto_color
, gboolean make_copy
)
900 GnmColor
*pattern_color
= style
->color
.pattern
;
902 if (pattern_color
->is_auto
&& auto_color
!= pattern_color
) {
903 style_color_ref (auto_color
);
905 GnmStyle
*orig
= style
;
906 style
= gnm_style_dup (style
);
907 gnm_style_unref (orig
);
909 gnm_style_set_pattern_color (style
, auto_color
);
915 * Replace auto border colors in style with sheet's auto pattern
916 * color. (pattern is *not* a typo.)
917 * make_copy tells if we are allowed to modify the style in place or we must
920 * FIXME: We conjecture that XL color 64 in border should change with the
921 * pattern, but not color 127. That distinction is not yet represented in
922 * our data structures.
925 link_border_colors (GnmStyle
*style
, GnmColor
*auto_color
, gboolean make_copy
)
929 for (i
= MSTYLE_BORDER_TOP
; i
<= MSTYLE_BORDER_DIAGONAL
; ++i
) {
930 if (elem_is_set (style
, i
)) {
932 style
->borders
[i
- MSTYLE_BORDER_TOP
];
938 color
= border
->color
;
939 if (color
->is_auto
&& auto_color
!= color
) {
940 GnmBorder
*new_border
;
941 GnmStyleBorderOrientation orientation
;
944 case MSTYLE_BORDER_LEFT
:
945 case MSTYLE_BORDER_RIGHT
:
946 orientation
= GNM_STYLE_BORDER_VERTICAL
;
948 case MSTYLE_BORDER_REV_DIAGONAL
:
949 case MSTYLE_BORDER_DIAGONAL
:
950 orientation
= GNM_STYLE_BORDER_DIAGONAL
;
952 case MSTYLE_BORDER_TOP
:
953 case MSTYLE_BORDER_BOTTOM
:
955 orientation
= GNM_STYLE_BORDER_HORIZONTAL
;
958 style_color_ref (auto_color
);
959 new_border
= gnm_style_border_fetch (
960 border
->line_type
, auto_color
,
964 GnmStyle
*orig
= style
;
965 style
= gnm_style_dup (style
);
966 gnm_style_unref (orig
);
969 gnm_style_set_border (style
, i
, new_border
);
977 gnm_style_linked_sheet_changed (GnmStyle
*style
)
979 Sheet
*sheet
= style
->linked_sheet
;
981 if (elem_is_set (style
, MSTYLE_VALIDATION
) &&
983 gnm_validation_get_sheet (style
->validation
) != sheet
) {
984 GnmValidation
*new_v
= gnm_validation_dup (style
->validation
);
985 gnm_validation_set_sheet (new_v
, sheet
);
986 gnm_style_set_validation (style
, new_v
);
989 if (elem_is_set (style
, MSTYLE_HLINK
) &&
991 gnm_hlink_get_sheet (style
->hlink
) != sheet
) {
992 GnmHLink
*new_l
= gnm_hlink_dup (style
->hlink
);
993 gnm_hlink_set_sheet (new_l
, sheet
);
994 gnm_style_set_hlink (style
, new_l
);
997 if (elem_is_set (style
, MSTYLE_CONDITIONS
) &&
999 gnm_style_conditions_get_sheet (style
->conditions
) != sheet
) {
1000 GnmStyleConditions
*new_c
= gnm_style_conditions_dup (style
->conditions
);
1001 gnm_style_conditions_set_sheet (new_c
, sheet
);
1002 gnm_style_set_conditions (style
, new_c
);
1007 * gnm_style_link_sheet :
1011 * ABSORBS a reference to the style and sets the link count to 1.
1013 * Where auto pattern color occurs in the style (it may for pattern and
1014 * borders), it is replaced with the sheet's auto pattern color. We make
1015 * sure that we do not modify the style which was passed in to us, but also
1016 * that we don't copy more than once. The final argument to the
1017 * link_xxxxx_color functions tell whether or not to copy.
1020 gnm_style_link_sheet (GnmStyle
*style
, Sheet
*sheet
)
1022 GnmColor
*auto_color
;
1023 gboolean style_is_orig
= TRUE
;
1025 if (style
->linked_sheet
!= NULL
) {
1026 GnmStyle
*orig
= style
;
1027 style
= gnm_style_dup (style
);
1028 gnm_style_unref (orig
);
1029 style_is_orig
= FALSE
;
1032 g_return_val_if_fail (style
->linked_sheet
!= sheet
, style
);
1035 g_return_val_if_fail (style
->link_count
== 0, style
);
1036 g_return_val_if_fail (style
->linked_sheet
== NULL
, style
);
1038 auto_color
= sheet_style_get_auto_pattern_color (sheet
);
1039 if (elem_is_set (style
, MSTYLE_COLOR_PATTERN
))
1040 style
= link_pattern_color (style
, auto_color
, style_is_orig
);
1041 style
= link_border_colors (style
, auto_color
, style_is_orig
);
1042 style_color_unref (auto_color
);
1044 style
->linked_sheet
= sheet
;
1045 style
->link_count
= 1;
1047 gnm_style_linked_sheet_changed (style
);
1049 d(("link sheet %p = 1\n", style
));
1054 gnm_style_link (GnmStyle
*style
)
1056 g_return_if_fail (style
->link_count
> 0);
1058 style
->link_count
++;
1059 d(("link %p = %d\n", style
, style
->link_count
));
1063 gnm_style_link_multiple (GnmStyle
*style
, int count
)
1065 g_return_if_fail (style
->link_count
> 0);
1067 style
->link_count
+= count
;
1068 d(("multiple link %p + %d = %d\n", style
, count
, style
->link_count
));
1072 gnm_style_unlink (GnmStyle
*style
)
1074 g_return_if_fail (style
->link_count
> 0);
1076 d(("unlink %p = %d\n", style
, style
->link_count
-1));
1077 if (style
->link_count
-- == 1) {
1078 sheet_style_unlink (style
->linked_sheet
, style
);
1079 style
->linked_sheet
= NULL
;
1080 gnm_style_unref (style
);
1084 // Internal function for sheet-style.c use only
1086 gnm_style_abandon_link (GnmStyle
*style
)
1088 style
->link_count
= 0;
1089 style
->linked_sheet
= NULL
;
1093 gnm_style_eq (GnmStyle
const *a
, GnmStyle
const *b
)
1099 gnm_style_equal (GnmStyle
const *a
, GnmStyle
const *b
)
1105 if (a
->set
!= b
->set
|| !gnm_style_equal_XL (a
, b
))
1107 UNROLLED_FOR (i
= MSTYLE_VALIDATION
, i
< MSTYLE_ELEMENT_MAX
, i
++, {
1108 if (elem_is_set (a
, i
) && !ELEM_IS_EQ (a
, b
, i
))
1116 gnm_style_equal_XL (GnmStyle
const *a
, GnmStyle
const *b
)
1120 g_return_val_if_fail (a
!= NULL
, FALSE
);
1121 g_return_val_if_fail (b
!= NULL
, FALSE
);
1126 if ((a
->set
^ b
->set
) & ((1u << MSTYLE_VALIDATION
) - 1))
1129 UNROLLED_FOR (i
= MSTYLE_COLOR_BACK
, i
< MSTYLE_VALIDATION
, i
++, {
1130 if (elem_is_set (a
, i
) && !ELEM_IS_EQ (a
, b
, i
))
1137 * gnm_style_equal_elem:
1142 * Returns: %TRUE, if the two styles have the same contents for the
1143 * given element, either because neither have it set, or because both
1144 * have it set and to the same value.
1147 gnm_style_equal_elem (GnmStyle
const *a
, GnmStyle
const *b
, GnmStyleElement e
)
1149 if (elem_is_set (a
, e
))
1150 return elem_is_set (b
, e
) && elem_is_eq (a
, b
, e
);
1152 return !elem_is_set (b
, e
);
1157 #define CMP_TRY_NUMBER_RAW(a_,b_) \
1159 if ((a_) < (b_)) return -1; \
1160 if ((a_) > (b_)) return -1; \
1163 #define CMP_TRY_NUMBER(e_,f_) \
1165 if (elem_is_set (a, (e_))) \
1166 CMP_TRY_NUMBER_RAW(a->f_, b->f_); \
1169 #define CMP_TRY_COLOR(e_,f_) \
1171 if (elem_is_set (a, (e_))) { \
1172 CMP_TRY_NUMBER_RAW(a->f_->is_auto, b->f_->is_auto); \
1173 CMP_TRY_NUMBER_RAW(a->f_->go_color, b->f_->go_color); \
1178 * Ordering of GnmStyles. Apart from FIXMEs, this shouldn't change
1179 * from one run to the next.
1182 gnm_style_cmp (GnmStyle
const *a
, GnmStyle
const *b
)
1190 * Very quick comparison based on what is set. This also allows
1191 * us to check on one elem_is_set below.
1193 CMP_TRY_NUMBER_RAW (a
->set
, b
->set
);
1195 CMP_TRY_COLOR (MSTYLE_FONT_COLOR
, color
.font
);
1196 CMP_TRY_COLOR (MSTYLE_COLOR_BACK
, color
.back
);
1197 CMP_TRY_COLOR (MSTYLE_COLOR_PATTERN
, color
.pattern
);
1198 for (e
= MSTYLE_BORDER_TOP
; e
<= MSTYLE_BORDER_DIAGONAL
; e
++) {
1199 GnmBorder
const *ba
, *bb
;
1200 if (!elem_is_set (a
, e
))
1202 ba
= a
->borders
[e
- MSTYLE_BORDER_TOP
];
1203 bb
= b
->borders
[e
- MSTYLE_BORDER_TOP
];
1205 continue; /* Handles both being NULL */
1206 CMP_TRY_NUMBER_RAW(!!ba
, !!bb
);
1207 CMP_TRY_NUMBER_RAW(ba
->line_type
, bb
->line_type
);
1208 CMP_TRY_NUMBER_RAW(ba
->color
->go_color
, bb
->color
->go_color
);
1209 CMP_TRY_NUMBER_RAW(ba
->begin_margin
, bb
->begin_margin
);
1210 CMP_TRY_NUMBER_RAW(ba
->end_margin
, bb
->end_margin
);
1211 CMP_TRY_NUMBER_RAW(ba
->width
, bb
->width
);
1213 CMP_TRY_NUMBER (MSTYLE_PATTERN
, pattern
);
1214 if (elem_is_set (a
, MSTYLE_FONT_NAME
)) {
1215 /* Plain strcmp, not utf-8. We need to see diffs. */
1216 int tmp
= strcmp (a
->font_detail
.name
->str
,
1217 b
->font_detail
.name
->str
);
1221 CMP_TRY_NUMBER (MSTYLE_FONT_BOLD
, font_detail
.bold
);
1222 CMP_TRY_NUMBER (MSTYLE_FONT_ITALIC
, font_detail
.italic
);
1223 CMP_TRY_NUMBER (MSTYLE_FONT_UNDERLINE
, font_detail
.underline
);
1224 CMP_TRY_NUMBER (MSTYLE_FONT_STRIKETHROUGH
, font_detail
.strikethrough
);
1225 CMP_TRY_NUMBER (MSTYLE_FONT_SCRIPT
, font_detail
.script
);
1226 CMP_TRY_NUMBER (MSTYLE_FONT_SIZE
, font_detail
.size
);
1227 if (elem_is_set (a
, MSTYLE_FORMAT
)) {
1228 /* Plain strcmp, not utf-8. We need to see diffs. */
1229 int tmp
= strcmp (go_format_as_XL (a
->format
),
1230 go_format_as_XL (b
->format
));
1234 CMP_TRY_NUMBER (MSTYLE_ALIGN_H
, h_align
);
1235 CMP_TRY_NUMBER (MSTYLE_ALIGN_V
, v_align
);
1236 CMP_TRY_NUMBER (MSTYLE_INDENT
, indent
);
1237 CMP_TRY_NUMBER (MSTYLE_ROTATION
, rotation
);
1238 CMP_TRY_NUMBER (MSTYLE_TEXT_DIR
, text_dir
);
1239 CMP_TRY_NUMBER (MSTYLE_WRAP_TEXT
, wrap_text
);
1240 CMP_TRY_NUMBER (MSTYLE_SHRINK_TO_FIT
, shrink_to_fit
);
1241 CMP_TRY_NUMBER (MSTYLE_CONTENTS_LOCKED
, contents_locked
);
1242 CMP_TRY_NUMBER (MSTYLE_CONTENTS_HIDDEN
, contents_hidden
);
1243 /* FIXME: validation */
1245 /* FIXME: input_msg */
1246 /* FIXME: conditions */
1247 /* FIXME: cond_styles */
1249 /* Last resort: pointer comparison. */
1250 return a
< b
? -1 : +1;
1253 #undef CMP_TRY_NUMBER
1254 #undef CMP_TRY_COLOR
1258 * gnm_style_equal_header :
1261 * @top: is this a header vertically or horizontally
1263 * Check to see if @a is different enough from @b to make us think that @a is
1267 gnm_style_equal_header (GnmStyle
const *a
, GnmStyle
const *b
, gboolean top
)
1269 int i
= top
? MSTYLE_BORDER_BOTTOM
: MSTYLE_BORDER_RIGHT
;
1271 if (!elem_is_eq (a
, b
, i
))
1273 for (i
= MSTYLE_COLOR_BACK
; i
<= MSTYLE_COLOR_PATTERN
; i
++)
1274 if (!elem_is_eq (a
, b
, i
))
1276 for (i
= MSTYLE_FONT_COLOR
; i
<= MSTYLE_SHRINK_TO_FIT
; i
++)
1277 if (!elem_is_eq (a
, b
, i
))
1284 gnm_style_is_element_set (GnmStyle
const *style
, GnmStyleElement elem
)
1286 g_return_val_if_fail (style
!= NULL
, FALSE
);
1287 g_return_val_if_fail (MSTYLE_COLOR_BACK
<= elem
&& elem
< MSTYLE_ELEMENT_MAX
, FALSE
);
1288 return elem_is_set (style
, elem
);
1292 * gnm_style_is_complete :
1295 * Returns TRUE if all elements are set.
1298 gnm_style_is_complete (GnmStyle
const *style
)
1300 g_return_val_if_fail (style
!= NULL
, FALSE
);
1302 return style
->set
== ((1u << MSTYLE_ELEMENT_MAX
) - 1);
1306 gnm_style_unset_element (GnmStyle
*style
, GnmStyleElement elem
)
1308 g_return_if_fail (style
!= NULL
);
1309 g_return_if_fail (MSTYLE_COLOR_BACK
<= elem
&& elem
< MSTYLE_ELEMENT_MAX
);
1311 if (elem_is_set (style
, elem
)) {
1312 elem_clear_contents (style
, elem
);
1313 elem_unset (style
, elem
);
1320 * @overlay: #GnmStyle
1322 * Applies all active elements of @overlay onto @base.
1325 gnm_style_merge (GnmStyle
*base
, GnmStyle
const *overlay
)
1328 if (base
== overlay
)
1330 for (i
= 0; i
< MSTYLE_ELEMENT_MAX
; i
++)
1331 if (elem_is_set (overlay
, i
)) {
1332 elem_clear_contents (base
, i
);
1333 elem_assign_contents (base
, overlay
, i
);
1334 elem_changed (base
, i
);
1339 * gnm_style_merge_element:
1340 * @dst: Destination style
1341 * @src: Source style
1342 * @elem: Element to replace
1344 * This function replaces element @elem in style @dst with element @elem
1345 * in style @src. (If element @elem was already set in style @dst then
1346 * the element will first be unset)
1349 gnm_style_merge_element (GnmStyle
*dst
, GnmStyle
const *src
, GnmStyleElement elem
)
1351 g_return_if_fail (src
!= NULL
);
1352 g_return_if_fail (dst
!= NULL
);
1353 g_return_if_fail (src
!= dst
);
1355 if (elem_is_set (src
, elem
)) {
1356 elem_clear_contents (dst
, elem
);
1357 elem_assign_contents (dst
, src
, elem
);
1358 elem_set (dst
, elem
);
1359 elem_changed (dst
, elem
);
1364 gnm_style_set_font_color (GnmStyle
*style
, GnmColor
*col
)
1366 g_return_if_fail (style
!= NULL
);
1367 g_return_if_fail (col
!= NULL
);
1369 elem_changed (style
, MSTYLE_FONT_COLOR
);
1370 if (elem_is_set (style
, MSTYLE_FONT_COLOR
))
1371 style_color_unref (style
->color
.font
);
1373 elem_set (style
, MSTYLE_FONT_COLOR
);
1374 elem_changed (style
, MSTYLE_FONT_COLOR
);
1375 style
->color
.font
= col
;
1376 gnm_style_clear_pango (style
);
1380 * gnm_style_set_back_color :
1384 * Assigns @col as the background of @style.
1386 * NOTE : the background colour is only visibile if
1387 * GnmStyle::pattern > 0
1390 gnm_style_set_back_color (GnmStyle
*style
, GnmColor
*col
)
1392 g_return_if_fail (style
!= NULL
);
1393 g_return_if_fail (col
!= NULL
);
1395 elem_changed (style
, MSTYLE_COLOR_BACK
);
1396 if (elem_is_set (style
, MSTYLE_COLOR_BACK
))
1397 style_color_unref (style
->color
.back
);
1399 elem_set (style
, MSTYLE_COLOR_BACK
);
1400 style
->color
.back
= col
;
1401 gnm_style_clear_pango (style
);
1404 gnm_style_set_pattern_color (GnmStyle
*style
, GnmColor
*col
)
1406 g_return_if_fail (style
!= NULL
);
1407 g_return_if_fail (col
!= NULL
);
1409 elem_changed (style
, MSTYLE_COLOR_PATTERN
);
1410 if (elem_is_set (style
, MSTYLE_COLOR_PATTERN
))
1411 style_color_unref (style
->color
.pattern
);
1413 elem_set (style
, MSTYLE_COLOR_PATTERN
);
1414 style
->color
.pattern
= col
;
1415 gnm_style_clear_pango (style
);
1419 gnm_style_get_font_color (GnmStyle
const *style
)
1421 g_return_val_if_fail (style
!= NULL
, NULL
);
1422 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_COLOR
), NULL
);
1423 return style
->color
.font
;
1427 gnm_style_get_back_color (GnmStyle
const *style
)
1429 g_return_val_if_fail (style
!= NULL
, NULL
);
1430 g_return_val_if_fail (elem_is_set (style
, MSTYLE_COLOR_BACK
), NULL
);
1431 return style
->color
.back
;
1435 gnm_style_get_pattern_color (GnmStyle
const *style
)
1437 g_return_val_if_fail (style
!= NULL
, NULL
);
1438 g_return_val_if_fail (elem_is_set (style
, MSTYLE_COLOR_PATTERN
), NULL
);
1439 return style
->color
.pattern
;
1443 gnm_style_set_border (GnmStyle
*style
, GnmStyleElement elem
,
1446 g_return_if_fail (style
!= NULL
);
1448 /* NOTE : It is legal for border to be NULL */
1450 case MSTYLE_ANY_BORDER
:
1451 elem_changed (style
, elem
);
1452 elem_set (style
, elem
);
1453 elem
-= MSTYLE_BORDER_TOP
;
1454 if (style
->borders
[elem
])
1455 gnm_style_border_unref (style
->borders
[elem
]);
1456 style
->borders
[elem
] = border
;
1459 g_warning ("Not a border element");
1465 gnm_style_get_border (GnmStyle
const *style
, GnmStyleElement elem
)
1467 g_return_val_if_fail (style
!= NULL
, NULL
);
1470 case MSTYLE_ANY_BORDER
:
1471 return style
->borders
[elem
- MSTYLE_BORDER_TOP
];
1474 g_warning ("Not a border element");
1480 gnm_style_set_pattern (GnmStyle
*style
, int pattern
)
1482 g_return_if_fail (style
!= NULL
);
1483 g_return_if_fail (pattern
>= 0);
1484 g_return_if_fail (pattern
< GNM_PATTERNS_MAX
);
1486 elem_changed (style
, MSTYLE_PATTERN
);
1487 elem_set (style
, MSTYLE_PATTERN
);
1488 style
->pattern
= pattern
;
1492 gnm_style_get_pattern (GnmStyle
const *style
)
1494 g_return_val_if_fail (style
!= NULL
, 0);
1495 g_return_val_if_fail (elem_is_set (style
, MSTYLE_PATTERN
), 0);
1497 return style
->pattern
;
1501 * gnm_style_get_font:
1503 * @context: #PangoContext
1505 * Returns: (transfer none):
1508 gnm_style_get_font (GnmStyle
const *style
, PangoContext
*context
)
1510 g_return_val_if_fail (style
!= NULL
, NULL
);
1512 if (!style
->font
|| style
->font_context
!= context
) {
1514 gboolean bold
, italic
;
1517 gnm_style_clear_font ((GnmStyle
*)style
);
1519 if (elem_is_set (style
, MSTYLE_FONT_NAME
))
1520 name
= gnm_style_get_font_name (style
);
1522 name
= DEFAULT_FONT
;
1524 if (elem_is_set (style
, MSTYLE_FONT_BOLD
))
1525 bold
= gnm_style_get_font_bold (style
);
1529 if (elem_is_set (style
, MSTYLE_FONT_ITALIC
))
1530 italic
= gnm_style_get_font_italic (style
);
1534 if (elem_is_set (style
, MSTYLE_FONT_SIZE
))
1535 size
= gnm_style_get_font_size (style
);
1537 size
= DEFAULT_SIZE
;
1539 ((GnmStyle
*)style
)->font
=
1540 gnm_font_new (context
, name
, size
, bold
, italic
);
1541 ((GnmStyle
*)style
)->font_context
= g_object_ref (context
);
1548 * gnm_style_set_font_name:
1549 * @style: the style to change
1550 * @name: the font name as a string
1554 gnm_style_set_font_name (GnmStyle
*style
, char const *name
)
1556 g_return_if_fail (name
!= NULL
);
1557 g_return_if_fail (style
!= NULL
);
1559 elem_changed (style
, MSTYLE_FONT_NAME
);
1560 if (elem_is_set (style
, MSTYLE_FONT_NAME
))
1561 go_string_unref (style
->font_detail
.name
);
1563 elem_set (style
, MSTYLE_FONT_NAME
);
1564 style
->font_detail
.name
= go_string_new (name
);
1565 gnm_style_clear_font (style
);
1566 gnm_style_clear_pango (style
);
1570 * gnm_style_get_font_name:
1571 * @style: the style to query
1573 * Returns: (transfer none): the currently set font name
1576 gnm_style_get_font_name (GnmStyle
const *style
)
1578 g_return_val_if_fail (style
!= NULL
, NULL
);
1579 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_NAME
), NULL
);
1581 return style
->font_detail
.name
->str
;
1585 gnm_style_set_font_bold (GnmStyle
*style
, gboolean bold
)
1587 g_return_if_fail (style
!= NULL
);
1589 elem_changed (style
, MSTYLE_FONT_BOLD
);
1590 elem_set (style
, MSTYLE_FONT_BOLD
);
1591 style
->font_detail
.bold
= !!bold
;
1592 gnm_style_clear_font (style
);
1593 gnm_style_clear_pango (style
);
1597 * gnm_style_get_font_bold:
1598 * @style: #GnmStyle to query
1600 * Returns: %TRUE if the style has a bold font.
1603 gnm_style_get_font_bold (GnmStyle
const *style
)
1605 g_return_val_if_fail (style
!= NULL
, FALSE
);
1606 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_BOLD
), FALSE
);
1608 return style
->font_detail
.bold
;
1612 gnm_style_set_font_italic (GnmStyle
*style
, gboolean italic
)
1614 g_return_if_fail (style
!= NULL
);
1616 elem_changed (style
, MSTYLE_FONT_ITALIC
);
1617 elem_set (style
, MSTYLE_FONT_ITALIC
);
1618 style
->font_detail
.italic
= !!italic
;
1619 gnm_style_clear_font (style
);
1620 gnm_style_clear_pango (style
);
1624 gnm_style_get_font_italic (GnmStyle
const *style
)
1626 g_return_val_if_fail (style
!= NULL
, FALSE
);
1627 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_ITALIC
), FALSE
);
1629 return style
->font_detail
.italic
;
1633 gnm_style_set_font_uline (GnmStyle
*style
, GnmUnderline
const underline
)
1635 g_return_if_fail (style
!= NULL
);
1636 g_return_if_fail (underline
>= UNDERLINE_NONE
&& underline
<= UNDERLINE_DOUBLE_LOW
);
1638 elem_changed (style
, MSTYLE_FONT_UNDERLINE
);
1639 elem_set (style
, MSTYLE_FONT_UNDERLINE
);
1640 style
->font_detail
.underline
= underline
;
1641 gnm_style_clear_pango (style
);
1645 gnm_style_get_font_uline (GnmStyle
const *style
)
1647 g_return_val_if_fail (style
!= NULL
, UNDERLINE_NONE
);
1648 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_UNDERLINE
), UNDERLINE_NONE
);
1650 return style
->font_detail
.underline
;
1654 gnm_style_set_font_strike (GnmStyle
*style
, gboolean strikethrough
)
1656 g_return_if_fail (style
!= NULL
);
1658 elem_changed (style
, MSTYLE_FONT_STRIKETHROUGH
);
1659 elem_set (style
, MSTYLE_FONT_STRIKETHROUGH
);
1660 style
->font_detail
.strikethrough
= !!strikethrough
;
1661 gnm_style_clear_pango (style
);
1665 gnm_style_get_font_strike (GnmStyle
const *style
)
1667 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_STRIKETHROUGH
), FALSE
);
1669 return style
->font_detail
.strikethrough
;
1673 gnm_style_set_font_script (GnmStyle
*style
, GOFontScript script
)
1675 g_return_if_fail (style
!= NULL
);
1676 elem_changed (style
, MSTYLE_FONT_SCRIPT
);
1677 elem_set (style
, MSTYLE_FONT_SCRIPT
);
1678 style
->font_detail
.script
= script
;
1679 gnm_style_clear_pango (style
);
1683 gnm_style_get_font_script (GnmStyle
const *style
)
1685 g_return_val_if_fail (style
!= NULL
, GO_FONT_SCRIPT_STANDARD
);
1686 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_SCRIPT
), GO_FONT_SCRIPT_STANDARD
);
1688 return style
->font_detail
.script
;
1692 gnm_style_set_font_size (GnmStyle
*style
, double size
)
1694 g_return_if_fail (style
!= NULL
);
1695 g_return_if_fail (size
>= 1.);
1696 elem_changed (style
, MSTYLE_FONT_SIZE
);
1697 elem_set (style
, MSTYLE_FONT_SIZE
);
1698 style
->font_detail
.size
= size
;
1699 gnm_style_clear_font (style
);
1700 gnm_style_clear_pango (style
);
1704 gnm_style_get_font_size (GnmStyle
const *style
)
1706 g_return_val_if_fail (style
!= NULL
, 12.0);
1707 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_SIZE
), 12.0);
1709 return style
->font_detail
.size
;
1713 gnm_style_set_format (GnmStyle
*style
, GOFormat
const *format
)
1715 g_return_if_fail (style
!= NULL
);
1716 g_return_if_fail (format
!= NULL
);
1718 elem_changed (style
, MSTYLE_FORMAT
);
1719 go_format_ref (format
);
1720 elem_clear_contents (style
, MSTYLE_FORMAT
);
1721 elem_set (style
, MSTYLE_FORMAT
);
1722 style
->format
= format
;
1726 * gnm_style_set_format_text:
1728 * @style: mstyle to change.
1729 * @format: An *untranslated* format string.
1732 gnm_style_set_format_text (GnmStyle
*style
, char const *format
)
1736 g_return_if_fail (style
!= NULL
);
1737 g_return_if_fail (format
!= NULL
);
1739 sf
= go_format_new_from_XL (format
);
1740 gnm_style_set_format (style
, sf
);
1741 go_format_unref (sf
);
1745 gnm_style_get_format (GnmStyle
const *style
)
1747 g_return_val_if_fail (style
!= NULL
, NULL
);
1748 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FORMAT
), NULL
);
1750 return style
->format
;
1754 gnm_style_set_align_h (GnmStyle
*style
, GnmHAlign a
)
1756 g_return_if_fail (style
!= NULL
);
1758 elem_changed (style
, MSTYLE_ALIGN_H
);
1759 elem_set (style
, MSTYLE_ALIGN_H
);
1764 gnm_style_get_align_h (GnmStyle
const *style
)
1766 g_return_val_if_fail (style
!= NULL
, GNM_HALIGN_LEFT
);
1767 g_return_val_if_fail (elem_is_set (style
, MSTYLE_ALIGN_H
), GNM_HALIGN_LEFT
);
1769 return style
->h_align
;
1773 gnm_style_set_align_v (GnmStyle
*style
, GnmVAlign a
)
1775 g_return_if_fail (style
!= NULL
);
1777 elem_changed (style
, MSTYLE_ALIGN_V
);
1778 elem_set (style
, MSTYLE_ALIGN_V
);
1783 gnm_style_get_align_v (GnmStyle
const *style
)
1785 g_return_val_if_fail (style
!= NULL
, GNM_VALIGN_TOP
);
1786 g_return_val_if_fail (elem_is_set (style
, MSTYLE_ALIGN_V
), GNM_VALIGN_TOP
);
1788 return style
->v_align
;
1792 gnm_style_set_indent (GnmStyle
*style
, int i
)
1794 g_return_if_fail (style
!= NULL
);
1796 elem_changed (style
, MSTYLE_INDENT
);
1797 elem_set (style
, MSTYLE_INDENT
);
1802 gnm_style_get_indent (GnmStyle
const *style
)
1804 g_return_val_if_fail (style
!= NULL
, 0);
1805 g_return_val_if_fail (elem_is_set (style
, MSTYLE_INDENT
), 0);
1807 return style
->indent
;
1811 gnm_style_set_rotation (GnmStyle
*style
, int rot_deg
)
1813 g_return_if_fail (style
!= NULL
);
1815 elem_changed (style
, MSTYLE_ROTATION
);
1816 elem_set (style
, MSTYLE_ROTATION
);
1817 style
->rotation
= rot_deg
;
1821 gnm_style_get_rotation (GnmStyle
const *style
)
1823 g_return_val_if_fail (style
!= NULL
, 0);
1824 g_return_val_if_fail (elem_is_set (style
, MSTYLE_ROTATION
), 0);
1826 return style
->rotation
;
1830 gnm_style_set_text_dir (GnmStyle
*style
, GnmTextDir text_dir
)
1832 g_return_if_fail (style
!= NULL
);
1834 elem_changed (style
, MSTYLE_TEXT_DIR
);
1835 elem_set (style
, MSTYLE_TEXT_DIR
);
1836 style
->text_dir
= text_dir
;
1840 gnm_style_get_text_dir (GnmStyle
const *style
)
1842 g_return_val_if_fail (style
!= NULL
, GNM_TEXT_DIR_CONTEXT
);
1843 g_return_val_if_fail (elem_is_set (style
, MSTYLE_TEXT_DIR
), GNM_TEXT_DIR_CONTEXT
);
1845 return style
->text_dir
;
1849 gnm_style_set_wrap_text (GnmStyle
*style
, gboolean f
)
1851 g_return_if_fail (style
!= NULL
);
1853 elem_changed (style
, MSTYLE_WRAP_TEXT
);
1854 elem_set (style
, MSTYLE_WRAP_TEXT
);
1855 style
->wrap_text
= !!f
;
1859 gnm_style_get_wrap_text (GnmStyle
const *style
)
1861 g_return_val_if_fail (elem_is_set (style
, MSTYLE_WRAP_TEXT
), FALSE
);
1863 return style
->wrap_text
;
1867 * Same as gnm_style_get_wrap_text except that if either halign or valign
1868 * is _JUSTIFY, the result will be TRUE.
1871 gnm_style_get_effective_wrap_text (GnmStyle
const *style
)
1873 g_return_val_if_fail (style
!= NULL
, FALSE
);
1874 g_return_val_if_fail (elem_is_set (style
, MSTYLE_WRAP_TEXT
), FALSE
);
1875 g_return_val_if_fail (elem_is_set (style
, MSTYLE_ALIGN_V
), FALSE
);
1876 g_return_val_if_fail (elem_is_set (style
, MSTYLE_ALIGN_H
), FALSE
);
1878 /* Note: GNM_HALIGN_GENERAL never expands to GNM_HALIGN_JUSTIFY. */
1879 return (style
->wrap_text
||
1880 style
->v_align
== GNM_VALIGN_JUSTIFY
||
1881 style
->v_align
== GNM_VALIGN_DISTRIBUTED
||
1882 style
->h_align
== GNM_HALIGN_JUSTIFY
);
1886 gnm_style_set_shrink_to_fit (GnmStyle
*style
, gboolean f
)
1888 g_return_if_fail (style
!= NULL
);
1890 elem_changed (style
, MSTYLE_SHRINK_TO_FIT
);
1891 elem_set (style
, MSTYLE_SHRINK_TO_FIT
);
1892 style
->shrink_to_fit
= !!f
;
1896 gnm_style_get_shrink_to_fit (GnmStyle
const *style
)
1898 g_return_val_if_fail (style
!= NULL
, FALSE
);
1899 g_return_val_if_fail (elem_is_set (style
, MSTYLE_SHRINK_TO_FIT
), FALSE
);
1901 return style
->shrink_to_fit
;
1905 gnm_style_set_contents_locked (GnmStyle
*style
, gboolean f
)
1907 g_return_if_fail (style
!= NULL
);
1909 elem_changed (style
, MSTYLE_CONTENTS_LOCKED
);
1910 elem_set (style
, MSTYLE_CONTENTS_LOCKED
);
1911 style
->contents_locked
= !!f
;
1915 gnm_style_get_contents_locked (GnmStyle
const *style
)
1917 g_return_val_if_fail (style
!= NULL
, FALSE
);
1918 g_return_val_if_fail (elem_is_set (style
, MSTYLE_CONTENTS_LOCKED
), FALSE
);
1920 return style
->contents_locked
;
1924 gnm_style_set_contents_hidden (GnmStyle
*style
, gboolean f
)
1926 g_return_if_fail (style
!= NULL
);
1928 elem_changed (style
, MSTYLE_CONTENTS_HIDDEN
);
1929 elem_set (style
, MSTYLE_CONTENTS_HIDDEN
);
1930 style
->contents_hidden
= !!f
;
1934 gnm_style_get_contents_hidden (GnmStyle
const *style
)
1936 g_return_val_if_fail (style
!= NULL
, FALSE
);
1937 g_return_val_if_fail (elem_is_set (style
, MSTYLE_CONTENTS_HIDDEN
), FALSE
);
1939 return style
->contents_hidden
;
1943 * gnm_style_set_validation:
1945 * @v: (transfer full): #GnmValidation
1948 gnm_style_set_validation (GnmStyle
*style
, GnmValidation
*v
)
1950 g_return_if_fail (style
!= NULL
);
1952 elem_clear_contents (style
, MSTYLE_VALIDATION
);
1953 elem_changed (style
, MSTYLE_VALIDATION
);
1954 elem_set (style
, MSTYLE_VALIDATION
);
1955 style
->validation
= v
;
1959 * gnm_style_get_validation:
1962 * Returns: (transfer none):
1964 GnmValidation
const *
1965 gnm_style_get_validation (GnmStyle
const *style
)
1967 g_return_val_if_fail (style
!= NULL
, NULL
);
1968 g_return_val_if_fail (elem_is_set (style
, MSTYLE_VALIDATION
), NULL
);
1970 return style
->validation
;
1974 * gnm_style_set_hlink:
1976 * @lnk: (transfer full): #GnmHLink
1978 * This sets a link for @style.
1981 gnm_style_set_hlink (GnmStyle
*style
, GnmHLink
*lnk
)
1983 g_return_if_fail (style
!= NULL
);
1985 elem_clear_contents (style
, MSTYLE_HLINK
);
1986 elem_changed (style
, MSTYLE_HLINK
);
1987 elem_set (style
, MSTYLE_HLINK
);
1992 * gnm_style_get_hlink:
1995 * Returns: (transfer none): the associated #GnmHLink.
1998 gnm_style_get_hlink (GnmStyle
const *style
)
2000 g_return_val_if_fail (style
!= NULL
, NULL
);
2001 g_return_val_if_fail (elem_is_set (style
, MSTYLE_HLINK
), NULL
);
2003 return style
->hlink
;
2007 * gnm_style_set_input_msg:
2009 * @msg: (transfer full): #GnmInputMsg
2011 * This sets an input message for @style.
2014 gnm_style_set_input_msg (GnmStyle
*style
, GnmInputMsg
*msg
)
2016 g_return_if_fail (style
!= NULL
);
2018 elem_clear_contents (style
, MSTYLE_INPUT_MSG
);
2019 elem_changed (style
, MSTYLE_INPUT_MSG
);
2020 elem_set (style
, MSTYLE_INPUT_MSG
);
2021 style
->input_msg
= msg
;
2025 * gnm_style_get_input_msg:
2028 * Returns: (transfer none): the currently set input message assuming
2029 * that the style has such.
2032 gnm_style_get_input_msg (GnmStyle
const *style
)
2034 g_return_val_if_fail (style
!= NULL
, NULL
);
2035 g_return_val_if_fail (elem_is_set (style
, MSTYLE_INPUT_MSG
), NULL
);
2037 return style
->input_msg
;
2041 * gnm_style_set_conditions:
2043 * @sc: (transfer full): #GnmStyleConditions
2045 * This sets conditional style for @style.
2048 gnm_style_set_conditions (GnmStyle
*style
, GnmStyleConditions
*sc
)
2050 g_return_if_fail (style
!= NULL
);
2052 elem_clear_contents (style
, MSTYLE_CONDITIONS
);
2053 elem_changed (style
, MSTYLE_CONDITIONS
);
2054 elem_set (style
, MSTYLE_CONDITIONS
);
2055 style
->conditions
= sc
;
2059 * gnm_style_get_conditions:
2062 * Returns: (transfer none): the currently set conditional style assuming
2063 * that the style has such.
2065 GnmStyleConditions
*
2066 gnm_style_get_conditions (GnmStyle
const *style
)
2068 g_return_val_if_fail (style
!= NULL
, NULL
);
2069 g_return_val_if_fail (elem_is_set (style
, MSTYLE_CONDITIONS
), NULL
);
2070 return style
->conditions
;
2074 * gnm_style_get_cond_style:
2076 * @ix: The index of the condition for which style is desired
2078 * Returns: (transfer none): the resulting style from applying the condition's
2079 * style overlay onto @style.
2082 gnm_style_get_cond_style (GnmStyle
const *style
, int ix
)
2084 g_return_val_if_fail (style
!= NULL
, NULL
);
2085 g_return_val_if_fail (elem_is_set (style
, MSTYLE_CONDITIONS
), NULL
);
2086 g_return_val_if_fail (style
->cond_styles
!= NULL
, NULL
);
2088 g_return_val_if_fail (ix
>= 0 && (unsigned)ix
< style
->cond_styles
->len
, NULL
);
2090 return g_ptr_array_index (style
->cond_styles
, ix
);
2096 debug_style_deps (void)
2098 static int debug
= -1;
2100 debug
= gnm_debug_flag ("style-deps");
2105 * Just a simple version for now. We can also ignore most function
2106 * calls[1] and self-references[2].
2108 * [1] Excluding volatile (TODAY, ...) and those that can create references
2109 * outside the arguments (INDIRECT).
2111 * [2] References that print like A1 when used in A1.
2114 cond_expr_harmless (GnmExpr
const *expr
)
2116 GnmValue
const *v
= gnm_expr_get_constant (expr
);
2117 if (v
&& !VALUE_IS_CELLRANGE (v
))
2125 gnm_style_link_dependents (GnmStyle
*style
, GnmRange
const *r
)
2127 GnmStyleConditions
*sc
;
2130 g_return_if_fail (style
!= NULL
);
2131 g_return_if_fail (r
!= NULL
);
2133 sheet
= style
->linked_sheet
;
2136 * Conditional formatting.
2138 * We need to trigger a reformatting of the cell if a cell referenced
2139 * by the condition changes.
2141 sc
= elem_is_set (style
, MSTYLE_CONDITIONS
)
2142 ? gnm_style_get_conditions (style
)
2145 GPtrArray
const *conds
= gnm_style_conditions_details (sc
);
2147 if (debug_style_deps ())
2148 g_printerr ("Linking %s for %p\n",
2149 range_as_string (r
), style
);
2150 for (ui
= 0; conds
&& ui
< conds
->len
; ui
++) {
2151 GnmStyleCond
const *c
= g_ptr_array_index (conds
, ui
);
2154 for (ei
= 0; ei
< 2; ei
++) {
2155 GnmExprTop
const *texpr
=
2156 gnm_style_cond_get_expr (c
, ei
);
2158 cond_expr_harmless (texpr
->expr
))
2161 style
->deps
= g_ptr_array_new ();
2162 gnm_dep_style_dependency
2163 (sheet
, texpr
, r
, style
->deps
);
2171 * We can probably ignore those. If a dependent cell changes such
2172 * that a validation condition is no longer satisfied, it is
2173 * grandfathered in as valid.
2176 /* The style owns the deps. */
2180 gnm_style_unlink_dependents (GnmStyle
*style
, GnmRange
const *r
)
2184 g_return_if_fail (style
!= NULL
);
2185 g_return_if_fail (r
!= NULL
);
2190 for (ui
= k
= 0; ui
< style
->deps
->len
; ui
++) {
2191 GnmDependent
*dep
= g_ptr_array_index (style
->deps
, ui
);
2192 GnmCellPos
const *pos
= dependent_pos (dep
);
2194 if (range_contains (r
, pos
->col
, pos
->row
)) {
2195 if (debug_style_deps ())
2196 g_printerr ("Unlinking %s for %p\n",
2197 cellpos_as_string (pos
), style
);
2198 dependent_set_expr (dep
, NULL
);
2201 g_ptr_array_index (style
->deps
, k
) = dep
;
2206 g_ptr_array_set_size (style
->deps
, k
);
2211 * gnm_style_visible_in_blank:
2212 * @style: style to query
2214 * Returns: %TRUE if the style is visible, i.e., not transparent. Specifically
2215 * that means if it has a background or a visible border.
2218 gnm_style_visible_in_blank (GnmStyle
const *style
)
2222 g_return_val_if_fail (style
!= NULL
, FALSE
);
2224 if (elem_is_set (style
, MSTYLE_PATTERN
) &&
2225 gnm_style_get_pattern (style
) > 0)
2228 for (i
= MSTYLE_BORDER_TOP
; i
<= MSTYLE_BORDER_DIAGONAL
; ++i
)
2229 if (elem_is_set (style
, i
) &&
2230 gnm_style_border_visible_in_blank (gnm_style_get_border (style
, i
)))
2237 add_attr (PangoAttrList
*attrs
, PangoAttribute
*attr
)
2239 attr
->start_index
= 0;
2240 attr
->end_index
= G_MAXINT
;
2241 pango_attr_list_insert (attrs
, attr
);
2245 * gnm_style_get_pango_attrs :
2249 gnm_style_get_pango_attrs (GnmStyle
const *style
,
2250 PangoContext
*context
,
2255 GnmFont
*font
= gnm_style_get_font (style
, context
);
2257 if (style
->pango_attrs
) {
2258 if (zoom
== style
->pango_attrs_zoom
) {
2259 pango_attr_list_ref (style
->pango_attrs
);
2260 return style
->pango_attrs
;
2262 pango_attr_list_unref (((GnmStyle
*)style
)->pango_attrs
);
2265 ((GnmStyle
*)style
)->pango_attrs
= l
= pango_attr_list_new ();
2266 ((GnmStyle
*)style
)->pango_attrs_zoom
= zoom
;
2267 ((GnmStyle
*)style
)->pango_attrs_height
= -1;
2269 /* Foreground colour. */
2270 /* See http://bugzilla.gnome.org/show_bug.cgi?id=105322 */
2272 GnmColor
const *fore
= style
->color
.font
;
2273 add_attr (l
, go_color_to_pango (fore
->go_color
, TRUE
));
2276 /* Handle underlining. */
2277 ul
= gnm_style_get_font_uline (style
);
2278 if (ul
!= UNDERLINE_NONE
)
2280 pango_attr_underline_new (gnm_translate_underline_to_pango (ul
)));
2282 /* Handle strikethrough. */
2283 if (gnm_style_get_font_strike (style
))
2284 add_attr (l
, pango_attr_strikethrough_new (TRUE
));
2286 /* Handle script. */
2287 switch (gnm_style_get_font_script (style
)) {
2289 case GO_FONT_SCRIPT_STANDARD
:
2291 case GO_FONT_SCRIPT_SUB
:
2292 add_attr (l
, go_pango_attr_subscript_new (TRUE
));
2294 case GO_FONT_SCRIPT_SUPER
:
2295 add_attr (l
, go_pango_attr_superscript_new (TRUE
));
2299 add_attr (l
, pango_attr_font_desc_new (font
->go
.font
->desc
));
2302 add_attr (l
, pango_attr_scale_new (zoom
));
2304 pango_attr_list_ref (l
);
2309 gnm_style_generate_attrs_full (GnmStyle
const *style
)
2311 GnmColor
const *fore
= style
->color
.font
;
2312 PangoAttrList
*l
= pango_attr_list_new ();
2314 add_attr (l
, pango_attr_family_new (gnm_style_get_font_name (style
)));
2315 add_attr (l
, pango_attr_size_new (gnm_style_get_font_size (style
) * PANGO_SCALE
));
2316 add_attr (l
, pango_attr_style_new (gnm_style_get_font_italic (style
)
2317 ? PANGO_STYLE_ITALIC
: PANGO_STYLE_NORMAL
));
2318 add_attr (l
, pango_attr_weight_new (gnm_style_get_font_bold (style
)
2319 ? PANGO_WEIGHT_BOLD
: PANGO_WEIGHT_NORMAL
));
2320 add_attr (l
, go_color_to_pango (fore
->go_color
, TRUE
));
2321 add_attr (l
, pango_attr_strikethrough_new
2322 (gnm_style_get_font_strike (style
)));
2323 add_attr (l
, pango_attr_underline_new
2324 (gnm_translate_underline_to_pango
2325 (gnm_style_get_font_uline (style
))));
2330 gnm_style_get_pango_height (GnmStyle
const *style
,
2331 PangoContext
*context
,
2334 PangoAttrList
*attrs
= gnm_style_get_pango_attrs (style
, context
, zoom
);
2336 if (style
->pango_attrs_height
== -1) {
2338 PangoLayout
*layout
= pango_layout_new (context
);
2339 GOFormat
const *fmt
;
2340 gboolean requires_translation
= FALSE
;
2342 fmt
= gnm_style_get_format (style
);
2343 if (!go_format_is_general (fmt
)) {
2344 GOFormatDetails details
;
2345 go_format_get_details (fmt
, &details
, NULL
);
2346 if (details
.family
== GO_FORMAT_SCIENTIFIC
&&
2347 details
.use_markup
) {
2349 = go_pango_attr_superscript_new (TRUE
);
2350 /* We want to superscript the "-01" in the */
2351 /* string "+1.23456789E-01" */
2352 a
->start_index
= 12;
2354 pango_attr_list_insert (attrs
, a
);
2355 requires_translation
= TRUE
;
2358 pango_layout_set_attributes (layout
, attrs
);
2359 pango_layout_set_text (layout
, "+1.23456789E-01", -1);
2360 if (requires_translation
)
2361 go_pango_translate_layout (layout
);
2362 pango_layout_get_pixel_size (layout
, NULL
, &h
);
2363 g_object_unref (layout
);
2364 ((GnmStyle
*)style
)->pango_attrs_height
= h
;
2367 pango_attr_list_unref (attrs
);
2368 return style
->pango_attrs_height
;
2373 gnm_style_set_from_pango_attribute (GnmStyle
*style
, PangoAttribute
const *attr
)
2375 switch (attr
->klass
->type
) {
2376 case PANGO_ATTR_FAMILY
:
2377 gnm_style_set_font_name (style
, ((PangoAttrString
*)attr
)->value
);
2379 case PANGO_ATTR_SIZE
:
2380 gnm_style_set_font_size (style
,
2381 ((PangoAttrInt
*)attr
)->value
/ (double)PANGO_SCALE
);
2383 case PANGO_ATTR_STYLE
:
2384 gnm_style_set_font_italic (style
,
2385 ((PangoAttrInt
*)attr
)->value
== PANGO_STYLE_ITALIC
);
2387 case PANGO_ATTR_WEIGHT
:
2388 gnm_style_set_font_bold (style
,
2389 ((PangoAttrInt
*)attr
)->value
>= PANGO_WEIGHT_BOLD
);
2391 case PANGO_ATTR_FOREGROUND
:
2392 gnm_style_set_font_color (style
, gnm_color_new_pango (
2393 &((PangoAttrColor
*)attr
)->color
));
2395 case PANGO_ATTR_UNDERLINE
:
2396 gnm_style_set_font_uline
2397 (style
, gnm_translate_underline_from_pango
2398 (((PangoAttrInt
*)attr
)->value
));
2400 case PANGO_ATTR_STRIKETHROUGH
:
2401 gnm_style_set_font_strike (style
,
2402 ((PangoAttrInt
*)attr
)->value
!= 0);
2405 gboolean script_seen
= FALSE
, script_set
= FALSE
;
2406 if (attr
->klass
->type
== go_pango_attr_superscript_get_attr_type ()) {
2408 if (((GOPangoAttrSuperscript
*)attr
)->val
== 1) {
2410 gnm_style_set_font_script
2411 (style
, GO_FONT_SCRIPT_SUPER
);
2413 } else if (attr
->klass
->type
== go_pango_attr_subscript_get_attr_type ()) {
2415 if (((GOPangoAttrSubscript
*)attr
)->val
== 1) {
2417 gnm_style_set_font_script
2418 (style
, GO_FONT_SCRIPT_SUB
);
2421 if (script_seen
&& !script_set
)
2422 gnm_style_set_font_script
2423 (style
, GO_FONT_SCRIPT_STANDARD
);
2424 break; /* ignored */
2429 /* ------------------------------------------------------------------------- */
2432 gnm_style_dump_color (GnmColor
*color
, GnmStyleElement elem
)
2435 g_printerr ("\t%s: %x:%x:%x%s\n",
2436 gnm_style_element_name
[elem
],
2437 GO_COLOR_UINT_R (color
->go_color
),
2438 GO_COLOR_UINT_G (color
->go_color
),
2439 GO_COLOR_UINT_B (color
->go_color
),
2440 color
->is_auto
? " auto" : "");
2442 g_printerr ("\t%s: (NULL)\n", gnm_style_element_name
[elem
]);
2446 gnm_style_dump_border (GnmBorder
*border
, GnmStyleElement elem
)
2448 g_printerr ("\t%s: ", gnm_style_element_name
[elem
]);
2450 g_printerr ("%d\n", border
->line_type
);
2452 g_printerr ("blank\n");
2457 * @style: style to dump
2459 * This function dumps the given style's contents to stderr. This is meant
2460 * for debug purposes only and doesn't do a very good job for, for example,
2461 * conditional style settings.
2464 gnm_style_dump (GnmStyle
const *style
)
2468 g_printerr ("Style Refs %d\n", style
->ref_count
);
2469 if (elem_is_set (style
, MSTYLE_COLOR_BACK
))
2470 gnm_style_dump_color (style
->color
.back
, MSTYLE_COLOR_BACK
);
2471 if (elem_is_set (style
, MSTYLE_COLOR_PATTERN
))
2472 gnm_style_dump_color (style
->color
.pattern
, MSTYLE_COLOR_PATTERN
);
2474 for (i
= MSTYLE_BORDER_TOP
; i
<= MSTYLE_BORDER_DIAGONAL
; ++i
)
2475 if (elem_is_set (style
, i
))
2476 gnm_style_dump_border (style
->borders
[i
-MSTYLE_BORDER_TOP
], i
);
2478 if (elem_is_set (style
, MSTYLE_PATTERN
))
2479 g_printerr ("\tpattern %d\n", style
->pattern
);
2480 if (elem_is_set (style
, MSTYLE_FONT_COLOR
))
2481 gnm_style_dump_color (style
->color
.font
, MSTYLE_FONT_COLOR
);
2482 if (elem_is_set (style
, MSTYLE_FONT_NAME
))
2483 g_printerr ("\tname '%s'\n", style
->font_detail
.name
->str
);
2484 if (elem_is_set (style
, MSTYLE_FONT_BOLD
))
2485 g_printerr (style
->font_detail
.bold
? "\tbold\n" : "\tnot bold\n");
2486 if (elem_is_set (style
, MSTYLE_FONT_ITALIC
))
2487 g_printerr (style
->font_detail
.italic
? "\titalic\n" : "\tnot italic\n");
2488 if (elem_is_set (style
, MSTYLE_FONT_UNDERLINE
))
2489 switch (style
->font_detail
.underline
) {
2491 case UNDERLINE_NONE
:
2492 g_printerr ("\tno underline\n"); break;
2493 case UNDERLINE_SINGLE
:
2494 g_printerr ("\tsingle underline\n"); break;
2495 case UNDERLINE_DOUBLE
:
2496 g_printerr ("\tdouble underline\n"); break;
2498 if (elem_is_set (style
, MSTYLE_FONT_STRIKETHROUGH
))
2499 g_printerr (style
->font_detail
.strikethrough
? "\tstrikethrough\n" : "\tno strikethrough\n");
2500 if (elem_is_set (style
, MSTYLE_FONT_SCRIPT
))
2501 switch (style
->font_detail
.script
) {
2502 case GO_FONT_SCRIPT_SUB
:
2503 g_printerr ("\tsubscript\n"); break;
2505 case GO_FONT_SCRIPT_STANDARD
:
2506 g_printerr ("\tno super or sub\n"); break;
2507 case GO_FONT_SCRIPT_SUPER
:
2508 g_printerr ("\tsuperscript\n"); break;
2510 if (elem_is_set (style
, MSTYLE_FONT_SIZE
))
2511 g_printerr ("\tsize %f\n", style
->font_detail
.size
);
2512 if (elem_is_set (style
, MSTYLE_FORMAT
)) {
2513 const char *fmt
= go_format_as_XL (style
->format
);
2514 g_printerr ("\tformat '%s'\n", fmt
);
2516 if (elem_is_set (style
, MSTYLE_ALIGN_V
))
2517 g_printerr ("\tvalign %hd\n", (short)style
->v_align
);
2518 if (elem_is_set (style
, MSTYLE_ALIGN_H
))
2519 g_printerr ("\thalign %hd\n", (short)style
->h_align
);
2520 if (elem_is_set (style
, MSTYLE_INDENT
))
2521 g_printerr ("\tindent %d\n", style
->indent
);
2522 if (elem_is_set (style
, MSTYLE_ROTATION
))
2523 g_printerr ("\trotation %d\n", style
->rotation
);
2524 if (elem_is_set (style
, MSTYLE_TEXT_DIR
))
2525 g_printerr ("\ttext dir %d\n", style
->text_dir
);
2526 if (elem_is_set (style
, MSTYLE_WRAP_TEXT
))
2527 g_printerr ("\twrap text %d\n", style
->wrap_text
);
2528 if (elem_is_set (style
, MSTYLE_SHRINK_TO_FIT
))
2529 g_printerr ("\tshrink to fit %d\n", style
->shrink_to_fit
);
2530 if (elem_is_set (style
, MSTYLE_CONTENTS_LOCKED
))
2531 g_printerr ("\tlocked %d\n", style
->contents_locked
);
2532 if (elem_is_set (style
, MSTYLE_CONTENTS_HIDDEN
))
2533 g_printerr ("\thidden %d\n", style
->contents_hidden
);
2534 if (elem_is_set (style
, MSTYLE_VALIDATION
))
2535 g_printerr ("\tvalidation %p\n", (void *)style
->validation
);
2536 if (elem_is_set (style
, MSTYLE_HLINK
))
2537 g_printerr ("\thlink %p\n", (void *)style
->hlink
);
2538 if (elem_is_set (style
, MSTYLE_INPUT_MSG
))
2539 g_printerr ("\tinput msg %p\n", (void *)style
->input_msg
);
2540 if (elem_is_set (style
, MSTYLE_CONDITIONS
))
2541 g_printerr ("\tconditions %p\n", (void *)style
->conditions
);
2544 /* ------------------------------------------------------------------------- */
2547 * gnm_style_init: (skip)
2550 gnm_style_init (void)
2554 go_mem_chunk_new ("style pool",
2562 cb_gnm_style_pool_leak (gpointer data
, G_GNUC_UNUSED gpointer user
)
2564 GnmStyle
*style
= data
;
2565 g_printerr ("Leaking style at %p.\n", (void *)style
);
2566 gnm_style_dump (style
);
2571 * gnm_style_shutdown: (skip)
2574 gnm_style_shutdown (void)
2577 go_mem_chunk_foreach_leak (gnm_style_pool
, cb_gnm_style_pool_leak
, NULL
);
2578 go_mem_chunk_destroy (gnm_style_pool
, FALSE
);
2579 gnm_style_pool
= NULL
;