1
1
# This effect works currently only with mono fonts
2
2
3
3
# MIT License
4
- # Copyright (c) 2020 Mike Schulze
4
+ # Copyright (c) 2023 Mike Schulze
5
5
# https://github.com/MikeSchulze/gdUnit3/blob/master/LICENSE
6
6
7
7
extends RichTextEffect
@@ -10,106 +10,102 @@ class_name RichTextEffectBackground
10
10
var bbcode = "bg"
11
11
12
12
var _label : WeakRef
13
- var _char_size :Vector2
14
- var _tab_size : int
15
- var _indent := Dictionary ()
16
- var diff_sub_color := Color (0 , 0 , 0 , 0 )
13
+ var _char_size := Vector2 ( 8 , 16 )
14
+ var _margin := Vector2 . ZERO
15
+ var _tab_size : int
16
+ var _diff_sub_color := Color (0 , 0 , 0 , 0 )
17
17
var _cache := Dictionary ()
18
18
19
+ class CharacterInfo :
20
+ var _position :Vector2
21
+ var _size :Vector2
22
+
23
+ func _init (position :Vector2 , size :Vector2 ):
24
+ _position = position
25
+ _size = size
26
+
27
+
19
28
func set_source (label :RichTextLabel ) -> void :
20
29
_label = weakref (label )
21
30
init_properties ()
22
31
32
+
23
33
func init_properties () :
24
34
_cache .clear ()
25
35
# determine character size
26
- var char_width := 8
27
- var char_height := 16
28
36
var custom_font = _label .get_ref ().get ("custom_fonts/mono_font" )
29
37
if custom_font is Font :
30
- char_height = custom_font .get_height ()
31
- char_width = custom_font .get_char_size (23 ).x
32
- _char_size = Vector2 (char_width , char_height )
38
+ _char_size = Vector2 (custom_font .get_char_size (23 ).x , custom_font .get_height ())
33
39
_tab_size = _label .get_ref ().tab_size
40
+ _margin = Vector2 (4 , 4 )
34
41
35
- func push_indent (line :int , indent :int ) -> void :
36
- _indent [line ] = indent
37
-
38
- func pop_indent (line :int , indent :int ) -> void :
39
- _indent [line + 1 ] = - indent
40
- _cache .clear ()
41
-
42
- func reset () -> void :
43
- _cache .clear ()
44
- _indent .clear ()
45
-
46
- func get_text_rect (control :Control ) -> Rect2 :
47
- var style : StyleBox = control .get_stylebox ("normal" )
48
- return Rect2 (style .get_offset (), control .get_size () - style .get_minimum_size ())
49
42
50
43
func _process_custom_fx (char_fx : CharFXTransform ) -> bool :
51
44
var label = _label .get_ref () as RichTextLabel
52
45
var scroll = label .get_v_scroll ()
53
- var position : = get_char_position (char_fx . absolute_index , label .get_text ())
54
-
55
- # padding
56
- position += Vector2 ( 4 , 4 )
46
+ var char_info : CharacterInfo = get_char_position (char_fx , label .get_text ())
47
+ var position := char_info . _position
48
+ # margin
49
+ position += _margin
57
50
# sync with scroll positon
58
51
position .y -= scroll .value
59
- var color = char_fx .env .get ("color" , diff_sub_color ) as Color
52
+ var color = char_fx .env .get ("color" , _diff_sub_color ) as Color
60
53
# lower the alpha for better backround
61
54
color .a = .3
62
- label .draw_rect (Rect2 (position , _char_size ), color )
63
-
55
+ label .draw_rect (Rect2 (position , char_info ._size ), color )
64
56
# increase the color lightning of the character (for better visualisation on background)
65
57
char_fx .color = char_fx .color .lightened (.8 )
66
58
return true
67
59
60
+
68
61
func _build_char_mapping (text :String ) -> Dictionary :
69
62
_cache .clear ()
70
63
var line_height := get_line_height ()
71
64
var line_index := 0
72
- var char_offset := 0
73
- var y_offset := 0
74
- var last_ident := 0
65
+ var char_index := 0
75
66
76
- # replace all tabs, otherwise it will results in invalid background coloring
77
- for line in text .replace ("\t " , "" ).split ("\n " ):
67
+ for line in text .split ("\n " ):
68
+ var position = Vector2 (0 , line_height * line_index )
69
+ for cp in line .length ():
70
+ var char_size := char_size (line , cp )
71
+ _cache [char_index ] = CharacterInfo .new (position , char_size )
72
+ # prints( "line:%d:%d" % [line_index, char_index], "'%s' (%d)" % [text[char_index], text.ord_at(char_index)], position, "ident", last_ident)#, "tab:", text[text_index] == "\t", char_size)
73
+ char_index += 1
74
+ position .x += char_size .x
78
75
line_index += 1
79
- # build line x_offset by current line indent
80
- last_ident = get_line_indent (line_index , last_ident )
81
- var x_offset = last_ident * _tab_size
82
-
83
- for x in line .length ():
84
- var char_index = char_offset + x
85
- _cache [char_index ] = Vector2 ((x_offset + x )* _char_size .x , y_offset )
86
- # calculate next line offsets
87
- y_offset += line_height
88
- char_offset += line .length ()
89
76
return _cache
90
77
91
- func get_char_position (char_index :int , text :String ) -> Vector2 :
78
+
79
+ func char_size (line :String , index :int ) -> Vector2 :
80
+ var character := line .ord_at (index )
81
+ match character :
82
+ 9 : return Vector2 (_tab_size * _char_size .x , _char_size .y )
83
+ _ : return _char_size
84
+ return _char_size
85
+
86
+
87
+ func get_char_position (char_fx : CharFXTransform , text :String ) -> CharacterInfo :
92
88
if _cache .empty ():
93
89
_build_char_mapping (text )
94
- return _cache .get (char_index , Vector2 .ONE )
90
+ return _cache .get (char_fx . absolute_index , CharacterInfo . new ( Vector2 .ZERO , _char_size ) )
95
91
96
- func get_line_indent (line :int , last_indent := 0 ) -> int :
97
- var line_indent = _indent .get (line , 0 )
98
- if line_indent == 0 :
99
- return last_indent
100
- if line_indent < 0 :
101
- return last_indent + line_indent
102
- return line_indent
103
92
104
93
func get_line_height () -> int :
105
94
var label = _label .get_ref () as RichTextLabel
106
95
var line_separation = label .get ("custom_constants/line_separation" )
107
96
if not line_separation :
108
97
line_separation = 1
109
- return get_char_size ().y + line_separation
98
+ return _char_size .y + line_separation
99
+
100
+
101
+ func get_text_rect (control :Control ) -> Rect2 :
102
+ var style : StyleBox = control .get_stylebox ("normal" )
103
+ return Rect2 (style .get_offset (), control .get_size () - style .get_minimum_size ())
104
+
105
+
106
+ func reset () -> void :
107
+ _cache .clear ()
110
108
111
- func get_char_size () -> Vector2 :
112
- return _char_size
113
109
114
110
func _notification (what ):
115
111
if what == EditorSettings .NOTIFICATION_EDITOR_SETTINGS_CHANGED :
0 commit comments