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:
1293 * @style: #GnmStyle to query
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:
1365 * @style: #GnmStyle to change
1366 * @col: (transfer full): #GnmColor
1368 * Set the color used for fonts.
1371 gnm_style_set_font_color (GnmStyle
*style
, GnmColor
*col
)
1373 g_return_if_fail (style
!= NULL
);
1374 g_return_if_fail (col
!= NULL
);
1376 elem_changed (style
, MSTYLE_FONT_COLOR
);
1377 if (elem_is_set (style
, MSTYLE_FONT_COLOR
))
1378 style_color_unref (style
->color
.font
);
1380 elem_set (style
, MSTYLE_FONT_COLOR
);
1381 elem_changed (style
, MSTYLE_FONT_COLOR
);
1382 style
->color
.font
= col
;
1383 gnm_style_clear_pango (style
);
1387 * gnm_style_set_back_color:
1388 * @style: #GnmStyle to change
1389 * @col: (transfer full): #GnmColor
1391 * Assigns @col as the background of @style.
1393 * NOTE: the background colour is only visibile if GnmStyle::pattern > 0
1396 gnm_style_set_back_color (GnmStyle
*style
, GnmColor
*col
)
1398 g_return_if_fail (style
!= NULL
);
1399 g_return_if_fail (col
!= NULL
);
1401 elem_changed (style
, MSTYLE_COLOR_BACK
);
1402 if (elem_is_set (style
, MSTYLE_COLOR_BACK
))
1403 style_color_unref (style
->color
.back
);
1405 elem_set (style
, MSTYLE_COLOR_BACK
);
1406 style
->color
.back
= col
;
1407 gnm_style_clear_pango (style
);
1411 * gnm_style_set_pattern_color:
1412 * @style: #GnmStyle to change
1413 * @col: (transfer full): #GnmColor
1415 * Set the color used for pattern.
1418 gnm_style_set_pattern_color (GnmStyle
*style
, GnmColor
*col
)
1420 g_return_if_fail (style
!= NULL
);
1421 g_return_if_fail (col
!= NULL
);
1423 elem_changed (style
, MSTYLE_COLOR_PATTERN
);
1424 if (elem_is_set (style
, MSTYLE_COLOR_PATTERN
))
1425 style_color_unref (style
->color
.pattern
);
1427 elem_set (style
, MSTYLE_COLOR_PATTERN
);
1428 style
->color
.pattern
= col
;
1429 gnm_style_clear_pango (style
);
1433 * gnm_style_get_font_color:
1434 * @style: #GnmStyle to query
1436 * Returns: (transfer none) (nullable): #GnmColor used for font.
1439 gnm_style_get_font_color (GnmStyle
const *style
)
1441 g_return_val_if_fail (style
!= NULL
, NULL
);
1442 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_COLOR
), NULL
);
1443 return style
->color
.font
;
1447 * gnm_style_get_back_color:
1448 * @style: #GnmStyle to query
1450 * Returns: (transfer none) (nullable): #GnmColor used for background.
1453 gnm_style_get_back_color (GnmStyle
const *style
)
1455 g_return_val_if_fail (style
!= NULL
, NULL
);
1456 g_return_val_if_fail (elem_is_set (style
, MSTYLE_COLOR_BACK
), NULL
);
1457 return style
->color
.back
;
1461 * gnm_style_get_pattern_color:
1462 * @style: #GnmStyle to query
1464 * Returns: (transfer none) (nullable): #GnmColor used for pattern.
1467 gnm_style_get_pattern_color (GnmStyle
const *style
)
1469 g_return_val_if_fail (style
!= NULL
, NULL
);
1470 g_return_val_if_fail (elem_is_set (style
, MSTYLE_COLOR_PATTERN
), NULL
);
1471 return style
->color
.pattern
;
1475 * gnm_style_set_border:
1476 * @style: #GnmStyle to change
1477 * @elem: Border element
1478 * @border: (transfer full) (nullable): new #GnmBorder for @style.
1481 gnm_style_set_border (GnmStyle
*style
, GnmStyleElement elem
,
1484 g_return_if_fail (style
!= NULL
);
1486 /* NOTE : It is legal for border to be NULL */
1488 case MSTYLE_ANY_BORDER
:
1489 elem_changed (style
, elem
);
1490 elem_set (style
, elem
);
1491 elem
-= MSTYLE_BORDER_TOP
;
1492 gnm_style_border_unref (style
->borders
[elem
]);
1493 style
->borders
[elem
] = border
;
1496 g_warning ("Not a border element");
1502 * gnm_style_get_border:
1503 * @style: #GnmStyle to query
1504 * @elem: Border element
1506 * Returns: (transfer none) (nullable): The #GnmBorder for a single
1510 gnm_style_get_border (GnmStyle
const *style
, GnmStyleElement elem
)
1512 g_return_val_if_fail (style
!= NULL
, NULL
);
1515 case MSTYLE_ANY_BORDER
:
1516 return style
->borders
[elem
- MSTYLE_BORDER_TOP
];
1519 g_warning ("Not a border element");
1525 * gnm_style_set_pattern:
1526 * @style: #GnmStyle to change
1527 * @pattern: pattern code
1530 gnm_style_set_pattern (GnmStyle
*style
, int pattern
)
1532 g_return_if_fail (style
!= NULL
);
1533 g_return_if_fail (pattern
>= 0);
1534 g_return_if_fail (pattern
< GNM_PATTERNS_MAX
);
1536 elem_changed (style
, MSTYLE_PATTERN
);
1537 elem_set (style
, MSTYLE_PATTERN
);
1538 style
->pattern
= pattern
;
1542 gnm_style_get_pattern (GnmStyle
const *style
)
1544 g_return_val_if_fail (style
!= NULL
, 0);
1545 g_return_val_if_fail (elem_is_set (style
, MSTYLE_PATTERN
), 0);
1547 return style
->pattern
;
1551 * gnm_style_get_font:
1552 * @style: #GnmStyle to query
1553 * @context: #PangoContext
1555 * Returns: (transfer none): GnmFont implied by @style.
1558 gnm_style_get_font (GnmStyle
const *style
, PangoContext
*context
)
1560 g_return_val_if_fail (style
!= NULL
, NULL
);
1562 if (!style
->font
|| style
->font_context
!= context
) {
1564 gboolean bold
, italic
;
1567 gnm_style_clear_font ((GnmStyle
*)style
);
1569 if (elem_is_set (style
, MSTYLE_FONT_NAME
))
1570 name
= gnm_style_get_font_name (style
);
1572 name
= DEFAULT_FONT
;
1574 if (elem_is_set (style
, MSTYLE_FONT_BOLD
))
1575 bold
= gnm_style_get_font_bold (style
);
1579 if (elem_is_set (style
, MSTYLE_FONT_ITALIC
))
1580 italic
= gnm_style_get_font_italic (style
);
1584 if (elem_is_set (style
, MSTYLE_FONT_SIZE
))
1585 size
= gnm_style_get_font_size (style
);
1587 size
= DEFAULT_SIZE
;
1589 ((GnmStyle
*)style
)->font
=
1590 gnm_font_new (context
, name
, size
, bold
, italic
);
1591 ((GnmStyle
*)style
)->font_context
= g_object_ref (context
);
1598 * gnm_style_set_font_name:
1599 * @style: #GnmStyle to change
1600 * @name: the font name as a string
1603 gnm_style_set_font_name (GnmStyle
*style
, char const *name
)
1605 g_return_if_fail (name
!= NULL
);
1606 g_return_if_fail (style
!= NULL
);
1608 elem_changed (style
, MSTYLE_FONT_NAME
);
1609 if (elem_is_set (style
, MSTYLE_FONT_NAME
))
1610 go_string_unref (style
->font_detail
.name
);
1612 elem_set (style
, MSTYLE_FONT_NAME
);
1613 style
->font_detail
.name
= go_string_new (name
);
1614 gnm_style_clear_font (style
);
1615 gnm_style_clear_pango (style
);
1619 * gnm_style_get_font_name:
1620 * @style: the style to query
1622 * Returns: (transfer none): the currently set font name
1625 gnm_style_get_font_name (GnmStyle
const *style
)
1627 g_return_val_if_fail (style
!= NULL
, NULL
);
1628 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_NAME
), NULL
);
1630 return style
->font_detail
.name
->str
;
1634 * gnm_style_set_font_bold:
1635 * @style: #GnmStyle to change
1636 * @bold: %TRUE for bold, %FALSE for regular
1639 gnm_style_set_font_bold (GnmStyle
*style
, gboolean bold
)
1641 g_return_if_fail (style
!= NULL
);
1643 elem_changed (style
, MSTYLE_FONT_BOLD
);
1644 elem_set (style
, MSTYLE_FONT_BOLD
);
1645 style
->font_detail
.bold
= !!bold
;
1646 gnm_style_clear_font (style
);
1647 gnm_style_clear_pango (style
);
1651 * gnm_style_get_font_bold:
1652 * @style: #GnmStyle to query
1654 * Returns: %TRUE if the style has a bold font.
1657 gnm_style_get_font_bold (GnmStyle
const *style
)
1659 g_return_val_if_fail (style
!= NULL
, FALSE
);
1660 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_BOLD
), FALSE
);
1662 return style
->font_detail
.bold
;
1666 * gnm_style_set_font_italic:
1667 * @style: #GnmStyle to change
1668 * @italic: %TRUE for italic, %FALSE for regular
1671 gnm_style_set_font_italic (GnmStyle
*style
, gboolean italic
)
1673 g_return_if_fail (style
!= NULL
);
1675 elem_changed (style
, MSTYLE_FONT_ITALIC
);
1676 elem_set (style
, MSTYLE_FONT_ITALIC
);
1677 style
->font_detail
.italic
= !!italic
;
1678 gnm_style_clear_font (style
);
1679 gnm_style_clear_pango (style
);
1683 * gnm_style_get_font_italic:
1684 * @style: #GnmStyle to query
1686 * Returns: %TRUE if the style has an italic font.
1689 gnm_style_get_font_italic (GnmStyle
const *style
)
1691 g_return_val_if_fail (style
!= NULL
, FALSE
);
1692 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_ITALIC
), FALSE
);
1694 return style
->font_detail
.italic
;
1698 * gnm_style_set_font_uline:
1699 * @style: #GnmStyle to change
1700 * @ul: #GnmUnderline specifying type of underlining
1703 gnm_style_set_font_uline (GnmStyle
*style
, GnmUnderline
const underline
)
1705 g_return_if_fail (style
!= NULL
);
1706 g_return_if_fail (underline
>= UNDERLINE_NONE
&& underline
<= UNDERLINE_DOUBLE_LOW
);
1708 elem_changed (style
, MSTYLE_FONT_UNDERLINE
);
1709 elem_set (style
, MSTYLE_FONT_UNDERLINE
);
1710 style
->font_detail
.underline
= underline
;
1711 gnm_style_clear_pango (style
);
1715 * gnm_style_get_font_uline:
1716 * @style: #GnmStyle to query
1718 * Returns: #GnmUnderline specifying type of underlining
1721 gnm_style_get_font_uline (GnmStyle
const *style
)
1723 g_return_val_if_fail (style
!= NULL
, UNDERLINE_NONE
);
1724 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_UNDERLINE
), UNDERLINE_NONE
);
1726 return style
->font_detail
.underline
;
1730 * gnm_style_set_font_strike:
1731 * @style: #GnmStyle to change
1732 * @strike: %TRUE for strikethrough, %FALSE for regular
1735 gnm_style_set_font_strike (GnmStyle
*style
, gboolean strikethrough
)
1737 g_return_if_fail (style
!= NULL
);
1739 elem_changed (style
, MSTYLE_FONT_STRIKETHROUGH
);
1740 elem_set (style
, MSTYLE_FONT_STRIKETHROUGH
);
1741 style
->font_detail
.strikethrough
= !!strikethrough
;
1742 gnm_style_clear_pango (style
);
1746 * gnm_style_get_font_strike:
1747 * @style: #GnmStyle to query
1749 * Returns: %TRUE for strikethrough, %FALSE for regular
1752 gnm_style_get_font_strike (GnmStyle
const *style
)
1754 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_STRIKETHROUGH
), FALSE
);
1756 return style
->font_detail
.strikethrough
;
1760 * gnm_style_set_font_script:
1761 * @style: #GnmStyle to change
1762 * @script: #GOFontScript specifying super or subscript
1765 gnm_style_set_font_script (GnmStyle
*style
, GOFontScript script
)
1767 g_return_if_fail (style
!= NULL
);
1768 elem_changed (style
, MSTYLE_FONT_SCRIPT
);
1769 elem_set (style
, MSTYLE_FONT_SCRIPT
);
1770 style
->font_detail
.script
= script
;
1771 gnm_style_clear_pango (style
);
1775 * gnm_style_get_font_script:
1776 * @style: #GnmStyle to query
1778 * Returns: #GOFontScript specifying super or subscript
1781 gnm_style_get_font_script (GnmStyle
const *style
)
1783 g_return_val_if_fail (style
!= NULL
, GO_FONT_SCRIPT_STANDARD
);
1784 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_SCRIPT
), GO_FONT_SCRIPT_STANDARD
);
1786 return style
->font_detail
.script
;
1790 * gnm_style_set_font_size:
1791 * @style: #GnmStyle to change
1792 * @size: Font size in points
1795 gnm_style_set_font_size (GnmStyle
*style
, double size
)
1797 g_return_if_fail (style
!= NULL
);
1798 g_return_if_fail (size
>= 1.);
1799 elem_changed (style
, MSTYLE_FONT_SIZE
);
1800 elem_set (style
, MSTYLE_FONT_SIZE
);
1801 style
->font_detail
.size
= size
;
1802 gnm_style_clear_font (style
);
1803 gnm_style_clear_pango (style
);
1807 * gnm_style_get_font_size:
1808 * @style: #GnmStyle to query
1810 * Returns: Font size in points
1813 gnm_style_get_font_size (GnmStyle
const *style
)
1815 g_return_val_if_fail (style
!= NULL
, 12.0);
1816 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FONT_SIZE
), 12.0);
1818 return style
->font_detail
.size
;
1822 * gnm_style_set_format:
1823 * @style: #GnmStyle to change
1827 gnm_style_set_format (GnmStyle
*style
, GOFormat
const *fmt
)
1829 g_return_if_fail (style
!= NULL
);
1830 g_return_if_fail (fmt
!= NULL
);
1832 elem_changed (style
, MSTYLE_FORMAT
);
1833 go_format_ref (fmt
);
1834 elem_clear_contents (style
, MSTYLE_FORMAT
);
1835 elem_set (style
, MSTYLE_FORMAT
);
1836 style
->format
= fmt
;
1840 * gnm_style_set_format_text:
1841 * @style: mstyle to change.
1842 * @format: An *untranslated* format string.
1845 gnm_style_set_format_text (GnmStyle
*style
, char const *format
)
1849 g_return_if_fail (style
!= NULL
);
1850 g_return_if_fail (format
!= NULL
);
1852 sf
= go_format_new_from_XL (format
);
1853 gnm_style_set_format (style
, sf
);
1854 go_format_unref (sf
);
1858 * gnm_style_get_format:
1859 * @style: #GnmStyle to query
1861 * Returns: (transfer none): #GOFormat
1864 gnm_style_get_format (GnmStyle
const *style
)
1866 g_return_val_if_fail (style
!= NULL
, NULL
);
1867 g_return_val_if_fail (elem_is_set (style
, MSTYLE_FORMAT
), NULL
);
1869 return style
->format
;
1873 * gnm_style_set_align_h:
1874 * @style: #GnmStyle to change
1878 gnm_style_set_align_h (GnmStyle
*style
, GnmHAlign a
)
1880 g_return_if_fail (style
!= NULL
);
1882 elem_changed (style
, MSTYLE_ALIGN_H
);
1883 elem_set (style
, MSTYLE_ALIGN_H
);
1888 * gnm_style_get_align_h:
1889 * @style: #GnmStyle to query
1891 * Returns: A #GnmHAlign
1894 gnm_style_get_align_h (GnmStyle
const *style
)
1896 g_return_val_if_fail (style
!= NULL
, GNM_HALIGN_LEFT
);
1897 g_return_val_if_fail (elem_is_set (style
, MSTYLE_ALIGN_H
), GNM_HALIGN_LEFT
);
1899 return style
->h_align
;
1903 * gnm_style_set_align_v:
1904 * @style: #GnmStyle to change
1908 gnm_style_set_align_v (GnmStyle
*style
, GnmVAlign a
)
1910 g_return_if_fail (style
!= NULL
);
1912 elem_changed (style
, MSTYLE_ALIGN_V
);
1913 elem_set (style
, MSTYLE_ALIGN_V
);
1918 * gnm_style_get_align_v:
1919 * @style: #GnmStyle to query
1921 * Returns: A #GnmVAlign
1924 gnm_style_get_align_v (GnmStyle
const *style
)
1926 g_return_val_if_fail (style
!= NULL
, GNM_VALIGN_TOP
);
1927 g_return_val_if_fail (elem_is_set (style
, MSTYLE_ALIGN_V
), GNM_VALIGN_TOP
);
1929 return style
->v_align
;
1933 * gnm_style_set_indent:
1934 * @style: #GnmStyle to change
1935 * @i: Indentation amount
1938 gnm_style_set_indent (GnmStyle
*style
, int i
)
1940 g_return_if_fail (style
!= NULL
);
1942 elem_changed (style
, MSTYLE_INDENT
);
1943 elem_set (style
, MSTYLE_INDENT
);
1948 * gnm_style_get_indent:
1949 * @style: #GnmStyle to query
1951 * Returns: Indentation amount
1954 gnm_style_get_indent (GnmStyle
const *style
)
1956 g_return_val_if_fail (style
!= NULL
, 0);
1957 g_return_val_if_fail (elem_is_set (style
, MSTYLE_INDENT
), 0);
1959 return style
->indent
;
1963 * gnm_style_set_rotation:
1964 * @style: #GnmStyle to change
1965 * @r: Rotation in degrees relative to horizontal
1968 gnm_style_set_rotation (GnmStyle
*style
, int rot_deg
)
1970 g_return_if_fail (style
!= NULL
);
1972 elem_changed (style
, MSTYLE_ROTATION
);
1973 elem_set (style
, MSTYLE_ROTATION
);
1974 style
->rotation
= rot_deg
;
1978 * gnm_style_get_rotation:
1979 * @style: #GnmStyle to query
1981 * Returns: Rotation in degrees relative to horizontal
1984 gnm_style_get_rotation (GnmStyle
const *style
)
1986 g_return_val_if_fail (style
!= NULL
, 0);
1987 g_return_val_if_fail (elem_is_set (style
, MSTYLE_ROTATION
), 0);
1989 return style
->rotation
;
1993 * gnm_style_set_text_dir:
1994 * @style: #GnmStyle to change
1995 * @text_dir: A #GnmTextDir
1998 gnm_style_set_text_dir (GnmStyle
*style
, GnmTextDir text_dir
)
2000 g_return_if_fail (style
!= NULL
);
2002 elem_changed (style
, MSTYLE_TEXT_DIR
);
2003 elem_set (style
, MSTYLE_TEXT_DIR
);
2004 style
->text_dir
= text_dir
;
2008 * gnm_style_get_text_dir:
2009 * @style: #GnmStyle to query
2011 * Returns: A #GnmTextDir
2014 gnm_style_get_text_dir (GnmStyle
const *style
)
2016 g_return_val_if_fail (style
!= NULL
, GNM_TEXT_DIR_CONTEXT
);
2017 g_return_val_if_fail (elem_is_set (style
, MSTYLE_TEXT_DIR
), GNM_TEXT_DIR_CONTEXT
);
2019 return style
->text_dir
;
2023 * gnm_style_set_wrap_text:
2024 * @style: #GnmStyle to change
2025 * @f: %TRUE for wrapping, %FALSE for not
2028 gnm_style_set_wrap_text (GnmStyle
*style
, gboolean f
)
2030 g_return_if_fail (style
!= NULL
);
2032 elem_changed (style
, MSTYLE_WRAP_TEXT
);
2033 elem_set (style
, MSTYLE_WRAP_TEXT
);
2034 style
->wrap_text
= !!f
;
2038 * gnm_style_get_wrap_text:
2039 * @style: #GnmStyle to query
2041 * Returns: %TRUE for wrapping, %FALSE for not. See also
2042 * gnm_style_get_effective_wrap_text.
2045 gnm_style_get_wrap_text (GnmStyle
const *style
)
2047 g_return_val_if_fail (elem_is_set (style
, MSTYLE_WRAP_TEXT
), FALSE
);
2049 return style
->wrap_text
;
2053 * gnm_style_get_effective_wrap_text:
2054 * @style: #GnmStyle to query
2056 * Returns: %TRUE for wrapping, %FALSE for not. This will be %TRUE also
2057 * when either alignment is JUSTIFY.
2060 gnm_style_get_effective_wrap_text (GnmStyle
const *style
)
2062 g_return_val_if_fail (style
!= NULL
, FALSE
);
2063 g_return_val_if_fail (elem_is_set (style
, MSTYLE_WRAP_TEXT
), FALSE
);
2064 g_return_val_if_fail (elem_is_set (style
, MSTYLE_ALIGN_V
), FALSE
);
2065 g_return_val_if_fail (elem_is_set (style
, MSTYLE_ALIGN_H
), FALSE
);
2067 /* Note: GNM_HALIGN_GENERAL never expands to GNM_HALIGN_JUSTIFY. */
2068 return (style
->wrap_text
||
2069 style
->v_align
== GNM_VALIGN_JUSTIFY
||
2070 style
->v_align
== GNM_VALIGN_DISTRIBUTED
||
2071 style
->h_align
== GNM_HALIGN_JUSTIFY
);
2075 * gnm_style_set_shrink_to_fit:
2076 * @style: #GnmStyle to change
2077 * @f: %TRUE for shrink-to-fit, %FALSE for not
2080 gnm_style_set_shrink_to_fit (GnmStyle
*style
, gboolean f
)
2082 g_return_if_fail (style
!= NULL
);
2084 elem_changed (style
, MSTYLE_SHRINK_TO_FIT
);
2085 elem_set (style
, MSTYLE_SHRINK_TO_FIT
);
2086 style
->shrink_to_fit
= !!f
;
2090 * gnm_style_get_shrink_to_fit:
2091 * @style: #GnmStyle to query
2093 * Returns: %TRUE for shrink-to-fit, %FALSE for not
2096 gnm_style_get_shrink_to_fit (GnmStyle
const *style
)
2098 g_return_val_if_fail (style
!= NULL
, FALSE
);
2099 g_return_val_if_fail (elem_is_set (style
, MSTYLE_SHRINK_TO_FIT
), FALSE
);
2101 return style
->shrink_to_fit
;
2105 * gnm_style_set_contents_locked:
2106 * @style: #GnmStyle to change
2107 * @f: %TRUE for locked, %FALSE for not
2110 gnm_style_set_contents_locked (GnmStyle
*style
, gboolean f
)
2112 g_return_if_fail (style
!= NULL
);
2114 elem_changed (style
, MSTYLE_CONTENTS_LOCKED
);
2115 elem_set (style
, MSTYLE_CONTENTS_LOCKED
);
2116 style
->contents_locked
= !!f
;
2120 * gnm_style_get_contents_locked:
2121 * @style: #GnmStyle to query
2123 * Returns: %TRUE for locked, %FALSE for not
2126 gnm_style_get_contents_locked (GnmStyle
const *style
)
2128 g_return_val_if_fail (style
!= NULL
, FALSE
);
2129 g_return_val_if_fail (elem_is_set (style
, MSTYLE_CONTENTS_LOCKED
), FALSE
);
2131 return style
->contents_locked
;
2135 * gnm_style_set_contents_hidden:
2136 * @style: #GnmStyle to change
2137 * @f: %TRUE for hidden, %FALSE for not
2140 gnm_style_set_contents_hidden (GnmStyle
*style
, gboolean f
)
2142 g_return_if_fail (style
!= NULL
);
2144 elem_changed (style
, MSTYLE_CONTENTS_HIDDEN
);
2145 elem_set (style
, MSTYLE_CONTENTS_HIDDEN
);
2146 style
->contents_hidden
= !!f
;
2150 * gnm_style_get_contents_hidden:
2151 * @style: #GnmStyle to query
2153 * Return: %TRUE for hidden, %FALSE for not
2156 gnm_style_get_contents_hidden (GnmStyle
const *style
)
2158 g_return_val_if_fail (style
!= NULL
, FALSE
);
2159 g_return_val_if_fail (elem_is_set (style
, MSTYLE_CONTENTS_HIDDEN
), FALSE
);
2161 return style
->contents_hidden
;
2165 * gnm_style_set_validation:
2166 * @style: #GnmStyle to change
2167 * @v: (transfer full): #GnmValidation
2170 gnm_style_set_validation (GnmStyle
*style
, GnmValidation
*v
)
2172 g_return_if_fail (style
!= NULL
);
2174 elem_clear_contents (style
, MSTYLE_VALIDATION
);
2175 elem_changed (style
, MSTYLE_VALIDATION
);
2176 elem_set (style
, MSTYLE_VALIDATION
);
2177 style
->validation
= v
;
2181 * gnm_style_get_validation:
2182 * @style: #GnmStyle to query
2184 * Returns: (transfer none):
2186 GnmValidation
const *
2187 gnm_style_get_validation (GnmStyle
const *style
)
2189 g_return_val_if_fail (style
!= NULL
, NULL
);
2190 g_return_val_if_fail (elem_is_set (style
, MSTYLE_VALIDATION
), NULL
);
2192 return style
->validation
;
2196 * gnm_style_set_hlink:
2197 * @style: #GnmStyle to change
2198 * @lnk: (transfer full) (nullable): #GnmHLink
2200 * This sets a link for @style.
2203 gnm_style_set_hlink (GnmStyle
*style
, GnmHLink
*lnk
)
2205 g_return_if_fail (style
!= NULL
);
2207 elem_clear_contents (style
, MSTYLE_HLINK
);
2208 elem_changed (style
, MSTYLE_HLINK
);
2209 elem_set (style
, MSTYLE_HLINK
);
2214 * gnm_style_get_hlink:
2215 * @style: #GnmStyle to query
2217 * Returns: (transfer none) (nullable): the associated #GnmHLink.
2220 gnm_style_get_hlink (GnmStyle
const *style
)
2222 g_return_val_if_fail (style
!= NULL
, NULL
);
2223 g_return_val_if_fail (elem_is_set (style
, MSTYLE_HLINK
), NULL
);
2225 return style
->hlink
;
2229 * gnm_style_set_input_msg:
2230 * @style: #GnmStyle to change
2231 * @msg: (transfer full) (nullable): #GnmInputMsg
2233 * This sets an input message for @style.
2236 gnm_style_set_input_msg (GnmStyle
*style
, GnmInputMsg
*msg
)
2238 g_return_if_fail (style
!= NULL
);
2240 elem_clear_contents (style
, MSTYLE_INPUT_MSG
);
2241 elem_changed (style
, MSTYLE_INPUT_MSG
);
2242 elem_set (style
, MSTYLE_INPUT_MSG
);
2243 style
->input_msg
= msg
;
2247 * gnm_style_get_input_msg:
2248 * @style: #GnmStyle to query
2250 * Returns: (transfer none) (nullable): the currently set input message.
2253 gnm_style_get_input_msg (GnmStyle
const *style
)
2255 g_return_val_if_fail (style
!= NULL
, NULL
);
2256 g_return_val_if_fail (elem_is_set (style
, MSTYLE_INPUT_MSG
), NULL
);
2258 return style
->input_msg
;
2262 * gnm_style_set_conditions:
2263 * @style: #GnmStyle to change
2264 * @sc: (transfer full): #GnmStyleConditions
2266 * This sets conditional style for @style.
2269 gnm_style_set_conditions (GnmStyle
*style
, GnmStyleConditions
*sc
)
2271 g_return_if_fail (style
!= NULL
);
2273 elem_clear_contents (style
, MSTYLE_CONDITIONS
);
2274 elem_changed (style
, MSTYLE_CONDITIONS
);
2275 elem_set (style
, MSTYLE_CONDITIONS
);
2276 style
->conditions
= sc
;
2280 * gnm_style_get_conditions:
2281 * @style: #GnmStyle to query
2283 * Returns: (transfer none) (nullable): the currently set conditional style.
2285 GnmStyleConditions
*
2286 gnm_style_get_conditions (GnmStyle
const *style
)
2288 g_return_val_if_fail (style
!= NULL
, NULL
);
2289 g_return_val_if_fail (elem_is_set (style
, MSTYLE_CONDITIONS
), NULL
);
2290 return style
->conditions
;
2294 * gnm_style_get_cond_style:
2295 * @style: #GnmStyle to query
2296 * @ix: The index of the condition for which style is desired
2298 * Returns: (transfer none): the resulting style from applying the condition's
2299 * style overlay onto @style.
2302 gnm_style_get_cond_style (GnmStyle
const *style
, int ix
)
2304 g_return_val_if_fail (style
!= NULL
, NULL
);
2305 g_return_val_if_fail (elem_is_set (style
, MSTYLE_CONDITIONS
), NULL
);
2306 g_return_val_if_fail (style
->cond_styles
!= NULL
, NULL
);
2308 g_return_val_if_fail (ix
>= 0 && (unsigned)ix
< style
->cond_styles
->len
, NULL
);
2310 return g_ptr_array_index (style
->cond_styles
, ix
);
2316 debug_style_deps (void)
2318 static int debug
= -1;
2320 debug
= gnm_debug_flag ("style-deps");
2325 * Just a simple version for now. We can also ignore most function
2326 * calls[1] and self-references[2].
2328 * [1] Excluding volatile (TODAY, ...) and those that can create references
2329 * outside the arguments (INDIRECT).
2331 * [2] References that print like A1 when used in A1.
2334 cond_expr_harmless (GnmExpr
const *expr
)
2336 GnmValue
const *v
= gnm_expr_get_constant (expr
);
2337 if (v
&& !VALUE_IS_CELLRANGE (v
))
2345 gnm_style_link_dependents (GnmStyle
*style
, GnmRange
const *r
)
2347 GnmStyleConditions
*sc
;
2350 g_return_if_fail (style
!= NULL
);
2351 g_return_if_fail (r
!= NULL
);
2353 sheet
= style
->linked_sheet
;
2356 * Conditional formatting.
2358 * We need to trigger a reformatting of the cell if a cell referenced
2359 * by the condition changes.
2361 sc
= elem_is_set (style
, MSTYLE_CONDITIONS
)
2362 ? gnm_style_get_conditions (style
)
2365 GPtrArray
const *conds
= gnm_style_conditions_details (sc
);
2367 if (debug_style_deps ())
2368 g_printerr ("Linking %s for %p\n",
2369 range_as_string (r
), style
);
2370 for (ui
= 0; conds
&& ui
< conds
->len
; ui
++) {
2371 GnmStyleCond
const *c
= g_ptr_array_index (conds
, ui
);
2374 for (ei
= 0; ei
< 2; ei
++) {
2375 GnmExprTop
const *texpr
=
2376 gnm_style_cond_get_expr (c
, ei
);
2378 cond_expr_harmless (texpr
->expr
))
2381 style
->deps
= g_ptr_array_new ();
2382 gnm_dep_style_dependency
2383 (sheet
, texpr
, r
, style
->deps
);
2391 * We can probably ignore those. If a dependent cell changes such
2392 * that a validation condition is no longer satisfied, it is
2393 * grandfathered in as valid.
2396 /* The style owns the deps. */
2400 gnm_style_unlink_dependents (GnmStyle
*style
, GnmRange
const *r
)
2404 g_return_if_fail (style
!= NULL
);
2405 g_return_if_fail (r
!= NULL
);
2410 for (ui
= k
= 0; ui
< style
->deps
->len
; ui
++) {
2411 GnmDependent
*dep
= g_ptr_array_index (style
->deps
, ui
);
2412 GnmCellPos
const *pos
= dependent_pos (dep
);
2414 if (range_contains (r
, pos
->col
, pos
->row
)) {
2415 if (debug_style_deps ())
2416 g_printerr ("Unlinking %s for %p\n",
2417 cellpos_as_string (pos
), style
);
2418 dependent_set_expr (dep
, NULL
);
2421 g_ptr_array_index (style
->deps
, k
) = dep
;
2426 g_ptr_array_set_size (style
->deps
, k
);
2431 * gnm_style_visible_in_blank:
2432 * @style: style to query
2434 * Returns: %TRUE if the style is visible, i.e., not transparent. Specifically
2435 * that means if it has a background or a visible border.
2438 gnm_style_visible_in_blank (GnmStyle
const *style
)
2442 g_return_val_if_fail (style
!= NULL
, FALSE
);
2444 if (elem_is_set (style
, MSTYLE_PATTERN
) &&
2445 gnm_style_get_pattern (style
) > 0)
2448 for (i
= MSTYLE_BORDER_TOP
; i
<= MSTYLE_BORDER_DIAGONAL
; ++i
)
2449 if (elem_is_set (style
, i
) &&
2450 gnm_style_border_visible_in_blank (gnm_style_get_border (style
, i
)))
2457 add_attr (PangoAttrList
*attrs
, PangoAttribute
*attr
)
2459 attr
->start_index
= 0;
2460 attr
->end_index
= G_MAXINT
;
2461 pango_attr_list_insert (attrs
, attr
);
2465 * gnm_style_generate_attrs:
2466 * @style: style to query
2468 * Returns: (transfer full): a #PangoAttrList with attributes matching
2469 * @style. Attributes where the default will serve are not included.
2470 * The foreground color is not included.
2473 gnm_style_get_pango_attrs (GnmStyle
const *style
,
2474 PangoContext
*context
,
2479 GnmFont
*font
= gnm_style_get_font (style
, context
);
2481 if (style
->pango_attrs
) {
2482 if (zoom
== style
->pango_attrs_zoom
) {
2483 pango_attr_list_ref (style
->pango_attrs
);
2484 return style
->pango_attrs
;
2486 pango_attr_list_unref (((GnmStyle
*)style
)->pango_attrs
);
2489 ((GnmStyle
*)style
)->pango_attrs
= l
= pango_attr_list_new ();
2490 ((GnmStyle
*)style
)->pango_attrs_zoom
= zoom
;
2491 ((GnmStyle
*)style
)->pango_attrs_height
= -1;
2493 /* Foreground colour. */
2494 /* See http://bugzilla.gnome.org/show_bug.cgi?id=105322 */
2496 GnmColor
const *fore
= style
->color
.font
;
2497 add_attr (l
, go_color_to_pango (fore
->go_color
, TRUE
));
2500 /* Handle underlining. */
2501 ul
= gnm_style_get_font_uline (style
);
2502 if (ul
!= UNDERLINE_NONE
)
2504 pango_attr_underline_new (gnm_translate_underline_to_pango (ul
)));
2506 /* Handle strikethrough. */
2507 if (gnm_style_get_font_strike (style
))
2508 add_attr (l
, pango_attr_strikethrough_new (TRUE
));
2510 /* Handle script. */
2511 switch (gnm_style_get_font_script (style
)) {
2513 case GO_FONT_SCRIPT_STANDARD
:
2515 case GO_FONT_SCRIPT_SUB
:
2516 add_attr (l
, go_pango_attr_subscript_new (TRUE
));
2518 case GO_FONT_SCRIPT_SUPER
:
2519 add_attr (l
, go_pango_attr_superscript_new (TRUE
));
2523 add_attr (l
, pango_attr_font_desc_new (font
->go
.font
->desc
));
2526 add_attr (l
, pango_attr_scale_new (zoom
));
2528 pango_attr_list_ref (l
);
2533 * gnm_style_generate_attrs_full:
2534 * @style: style to query
2536 * Returns: (transfer full): a #PangoAttrList with attributes matching
2537 * @style, even attributes where the default would have served.
2540 gnm_style_generate_attrs_full (GnmStyle
const *style
)
2542 GnmColor
const *fore
= style
->color
.font
;
2543 PangoAttrList
*l
= pango_attr_list_new ();
2545 add_attr (l
, pango_attr_family_new (gnm_style_get_font_name (style
)));
2546 add_attr (l
, pango_attr_size_new (gnm_style_get_font_size (style
) * PANGO_SCALE
));
2547 add_attr (l
, pango_attr_style_new (gnm_style_get_font_italic (style
)
2548 ? PANGO_STYLE_ITALIC
: PANGO_STYLE_NORMAL
));
2549 add_attr (l
, pango_attr_weight_new (gnm_style_get_font_bold (style
)
2550 ? PANGO_WEIGHT_BOLD
: PANGO_WEIGHT_NORMAL
));
2551 add_attr (l
, go_color_to_pango (fore
->go_color
, TRUE
));
2552 add_attr (l
, pango_attr_strikethrough_new
2553 (gnm_style_get_font_strike (style
)));
2554 add_attr (l
, pango_attr_underline_new
2555 (gnm_translate_underline_to_pango
2556 (gnm_style_get_font_uline (style
))));
2561 gnm_style_get_pango_height (GnmStyle
const *style
,
2562 PangoContext
*context
,
2565 PangoAttrList
*attrs
= gnm_style_get_pango_attrs (style
, context
, zoom
);
2567 if (style
->pango_attrs_height
== -1) {
2569 PangoLayout
*layout
= pango_layout_new (context
);
2570 GOFormat
const *fmt
;
2571 gboolean requires_translation
= FALSE
;
2573 fmt
= gnm_style_get_format (style
);
2574 if (!go_format_is_general (fmt
)) {
2575 GOFormatDetails details
;
2576 go_format_get_details (fmt
, &details
, NULL
);
2577 if (details
.family
== GO_FORMAT_SCIENTIFIC
&&
2578 details
.use_markup
) {
2580 = go_pango_attr_superscript_new (TRUE
);
2581 /* We want to superscript the "-01" in the */
2582 /* string "+1.23456789E-01" */
2583 a
->start_index
= 12;
2585 pango_attr_list_insert (attrs
, a
);
2586 requires_translation
= TRUE
;
2589 pango_layout_set_attributes (layout
, attrs
);
2590 pango_layout_set_text (layout
, "+1.23456789E-01", -1);
2591 if (requires_translation
)
2592 go_pango_translate_layout (layout
);
2593 pango_layout_get_pixel_size (layout
, NULL
, &h
);
2594 g_object_unref (layout
);
2595 ((GnmStyle
*)style
)->pango_attrs_height
= h
;
2598 pango_attr_list_unref (attrs
);
2599 return style
->pango_attrs_height
;
2604 gnm_style_set_from_pango_attribute (GnmStyle
*style
, PangoAttribute
const *attr
)
2606 switch (attr
->klass
->type
) {
2607 case PANGO_ATTR_FAMILY
:
2608 gnm_style_set_font_name (style
, ((PangoAttrString
*)attr
)->value
);
2610 case PANGO_ATTR_SIZE
:
2611 gnm_style_set_font_size (style
,
2612 ((PangoAttrInt
*)attr
)->value
/ (double)PANGO_SCALE
);
2614 case PANGO_ATTR_STYLE
:
2615 gnm_style_set_font_italic (style
,
2616 ((PangoAttrInt
*)attr
)->value
== PANGO_STYLE_ITALIC
);
2618 case PANGO_ATTR_WEIGHT
:
2619 gnm_style_set_font_bold (style
,
2620 ((PangoAttrInt
*)attr
)->value
>= PANGO_WEIGHT_BOLD
);
2622 case PANGO_ATTR_FOREGROUND
:
2623 gnm_style_set_font_color (style
, gnm_color_new_pango (
2624 &((PangoAttrColor
*)attr
)->color
));
2626 case PANGO_ATTR_UNDERLINE
:
2627 gnm_style_set_font_uline
2628 (style
, gnm_translate_underline_from_pango
2629 (((PangoAttrInt
*)attr
)->value
));
2631 case PANGO_ATTR_STRIKETHROUGH
:
2632 gnm_style_set_font_strike (style
,
2633 ((PangoAttrInt
*)attr
)->value
!= 0);
2636 gboolean script_seen
= FALSE
, script_set
= FALSE
;
2637 if (attr
->klass
->type
== go_pango_attr_superscript_get_attr_type ()) {
2639 if (((GOPangoAttrSuperscript
*)attr
)->val
== 1) {
2641 gnm_style_set_font_script
2642 (style
, GO_FONT_SCRIPT_SUPER
);
2644 } else if (attr
->klass
->type
== go_pango_attr_subscript_get_attr_type ()) {
2646 if (((GOPangoAttrSubscript
*)attr
)->val
== 1) {
2648 gnm_style_set_font_script
2649 (style
, GO_FONT_SCRIPT_SUB
);
2652 if (script_seen
&& !script_set
)
2653 gnm_style_set_font_script
2654 (style
, GO_FONT_SCRIPT_STANDARD
);
2655 break; /* ignored */
2660 /* ------------------------------------------------------------------------- */
2663 gnm_style_dump_color (GnmColor
*color
, GnmStyleElement elem
)
2666 g_printerr ("\t%s: %x:%x:%x%s\n",
2667 gnm_style_element_name
[elem
],
2668 GO_COLOR_UINT_R (color
->go_color
),
2669 GO_COLOR_UINT_G (color
->go_color
),
2670 GO_COLOR_UINT_B (color
->go_color
),
2671 color
->is_auto
? " auto" : "");
2673 g_printerr ("\t%s: (NULL)\n", gnm_style_element_name
[elem
]);
2677 gnm_style_dump_border (GnmBorder
*border
, GnmStyleElement elem
)
2679 g_printerr ("\t%s: ", gnm_style_element_name
[elem
]);
2681 g_printerr ("%d\n", border
->line_type
);
2683 g_printerr ("blank\n");
2688 * @style: style to dump
2690 * This function dumps the given style's contents to stderr. This is meant
2691 * for debug purposes only and doesn't do a very good job for, for example,
2692 * conditional style settings.
2695 gnm_style_dump (GnmStyle
const *style
)
2699 g_printerr ("Style Refs %d\n", style
->ref_count
);
2700 if (elem_is_set (style
, MSTYLE_COLOR_BACK
))
2701 gnm_style_dump_color (style
->color
.back
, MSTYLE_COLOR_BACK
);
2702 if (elem_is_set (style
, MSTYLE_COLOR_PATTERN
))
2703 gnm_style_dump_color (style
->color
.pattern
, MSTYLE_COLOR_PATTERN
);
2705 for (i
= MSTYLE_BORDER_TOP
; i
<= MSTYLE_BORDER_DIAGONAL
; ++i
)
2706 if (elem_is_set (style
, i
))
2707 gnm_style_dump_border (style
->borders
[i
-MSTYLE_BORDER_TOP
], i
);
2709 if (elem_is_set (style
, MSTYLE_PATTERN
))
2710 g_printerr ("\tpattern %d\n", style
->pattern
);
2711 if (elem_is_set (style
, MSTYLE_FONT_COLOR
))
2712 gnm_style_dump_color (style
->color
.font
, MSTYLE_FONT_COLOR
);
2713 if (elem_is_set (style
, MSTYLE_FONT_NAME
))
2714 g_printerr ("\tname '%s'\n", style
->font_detail
.name
->str
);
2715 if (elem_is_set (style
, MSTYLE_FONT_BOLD
))
2716 g_printerr (style
->font_detail
.bold
? "\tbold\n" : "\tnot bold\n");
2717 if (elem_is_set (style
, MSTYLE_FONT_ITALIC
))
2718 g_printerr (style
->font_detail
.italic
? "\titalic\n" : "\tnot italic\n");
2719 if (elem_is_set (style
, MSTYLE_FONT_UNDERLINE
))
2720 switch (style
->font_detail
.underline
) {
2722 case UNDERLINE_NONE
:
2723 g_printerr ("\tno underline\n"); break;
2724 case UNDERLINE_SINGLE
:
2725 g_printerr ("\tsingle underline\n"); break;
2726 case UNDERLINE_DOUBLE
:
2727 g_printerr ("\tdouble underline\n"); break;
2729 if (elem_is_set (style
, MSTYLE_FONT_STRIKETHROUGH
))
2730 g_printerr (style
->font_detail
.strikethrough
? "\tstrikethrough\n" : "\tno strikethrough\n");
2731 if (elem_is_set (style
, MSTYLE_FONT_SCRIPT
))
2732 switch (style
->font_detail
.script
) {
2733 case GO_FONT_SCRIPT_SUB
:
2734 g_printerr ("\tsubscript\n"); break;
2736 case GO_FONT_SCRIPT_STANDARD
:
2737 g_printerr ("\tno super or sub\n"); break;
2738 case GO_FONT_SCRIPT_SUPER
:
2739 g_printerr ("\tsuperscript\n"); break;
2741 if (elem_is_set (style
, MSTYLE_FONT_SIZE
))
2742 g_printerr ("\tsize %f\n", style
->font_detail
.size
);
2743 if (elem_is_set (style
, MSTYLE_FORMAT
)) {
2744 const char *fmt
= go_format_as_XL (style
->format
);
2745 g_printerr ("\tformat '%s'\n", fmt
);
2747 if (elem_is_set (style
, MSTYLE_ALIGN_V
))
2748 g_printerr ("\tvalign %hd\n", (short)style
->v_align
);
2749 if (elem_is_set (style
, MSTYLE_ALIGN_H
))
2750 g_printerr ("\thalign %hd\n", (short)style
->h_align
);
2751 if (elem_is_set (style
, MSTYLE_INDENT
))
2752 g_printerr ("\tindent %d\n", style
->indent
);
2753 if (elem_is_set (style
, MSTYLE_ROTATION
))
2754 g_printerr ("\trotation %d\n", style
->rotation
);
2755 if (elem_is_set (style
, MSTYLE_TEXT_DIR
))
2756 g_printerr ("\ttext dir %d\n", style
->text_dir
);
2757 if (elem_is_set (style
, MSTYLE_WRAP_TEXT
))
2758 g_printerr ("\twrap text %d\n", style
->wrap_text
);
2759 if (elem_is_set (style
, MSTYLE_SHRINK_TO_FIT
))
2760 g_printerr ("\tshrink to fit %d\n", style
->shrink_to_fit
);
2761 if (elem_is_set (style
, MSTYLE_CONTENTS_LOCKED
))
2762 g_printerr ("\tlocked %d\n", style
->contents_locked
);
2763 if (elem_is_set (style
, MSTYLE_CONTENTS_HIDDEN
))
2764 g_printerr ("\thidden %d\n", style
->contents_hidden
);
2765 if (elem_is_set (style
, MSTYLE_VALIDATION
))
2766 g_printerr ("\tvalidation %p\n", (void *)style
->validation
);
2767 if (elem_is_set (style
, MSTYLE_HLINK
))
2768 g_printerr ("\thlink %p\n", (void *)style
->hlink
);
2769 if (elem_is_set (style
, MSTYLE_INPUT_MSG
))
2770 g_printerr ("\tinput msg %p\n", (void *)style
->input_msg
);
2771 if (elem_is_set (style
, MSTYLE_CONDITIONS
))
2772 g_printerr ("\tconditions %p\n", (void *)style
->conditions
);
2775 /* ------------------------------------------------------------------------- */
2778 * gnm_style_init: (skip)
2781 gnm_style_init (void)
2785 go_mem_chunk_new ("style pool",
2793 cb_gnm_style_pool_leak (gpointer data
, G_GNUC_UNUSED gpointer user
)
2795 GnmStyle
*style
= data
;
2796 g_printerr ("Leaking style at %p.\n", (void *)style
);
2797 gnm_style_dump (style
);
2802 * gnm_style_shutdown: (skip)
2805 gnm_style_shutdown (void)
2808 go_mem_chunk_foreach_leak (gnm_style_pool
, cb_gnm_style_pool_leak
, NULL
);
2809 go_mem_chunk_destroy (gnm_style_pool
, FALSE
);
2810 gnm_style_pool
= NULL
;