/
TextServiceUtils.lua
133 lines (105 loc) · 3.51 KB
/
TextServiceUtils.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
--[=[
@class TextServiceUtils
]=]
local TextService = game:GetService("TextService")
local require = require(script.Parent.loader).load(script)
local Blend = require("Blend")
local Promise = require("Promise")
local Rx = require("Rx")
local TextServiceUtils = {}
--[=[
Gets the size for the label using legacy API surface.
:::warning
This will not handle new font faces well.
:::
@param textLabel TextLabel
@param text string
@param maxWidth number
@return Promise<Vector2>
]=]
function TextServiceUtils.getSizeForLabel(textLabel, text, maxWidth)
assert(typeof(textLabel) == "Instance", "Bad textLabel")
assert(type(text) == "string", "Bad text")
maxWidth = maxWidth or 1e6
assert(maxWidth > 0, "Bad maxWidth")
return TextService:GetTextSize(text, textLabel.TextSize, textLabel.Font, Vector2.new(maxWidth, 1e6))
end
--[=[
Promises the text bounds for the given parameters
@param params GetTextBoundsParams
@return Promise<Vector2>
]=]
function TextServiceUtils.promiseTextBounds(params)
assert(typeof(params) == "Instance" and params:IsA("GetTextBoundsParams"), "Bad params")
return Promise.spawn(function(resolve, reject)
local size
local ok, err = pcall(function()
size = TextService:GetTextBoundsAsync(params)
end)
if not ok then
return reject(err)
end
return resolve(size)
end)
end
--[=[
Observes the current size for the current props. The properties
can be anything [Blend] would accept as an input. If FontFace is defined,
it will be used before Font. The following properties are available:
* `Text` - string
* `TextSize` - number
* `Font` - [Enum.Font]
* `FontFace` [Font]
* `MaxSize` - [Vector2]
* `LineHeight` - number
```lua
local stringValue = Instance.new("StringValue")
stringValue.Text = "Hello"
local observe = TextServiceUtils.observeSizeForLabelProps({
Text = stringValue;
Font = Enum.Font.;
MaxSize = Vector2.new(250, 100);
TextSize = 24;
})
-- Be sure to clean up the subscription
observe:Subscribe(function(size)
print(size)
end)
```
@param props table
@return Observable<Vector2> -- The text bounds reported
]=]
function TextServiceUtils.observeSizeForLabelProps(props)
assert(props.Text, "Bad props.Text")
assert(props.TextSize, "Bad props.TextSize")
if not (props.Font or props.FontFace) then
error("Bad props.Font or props.FontFace")
end
return Rx.combineLatest({
Text = Blend.toPropertyObservable(props.Text) or props.Text,
TextSize = Blend.toPropertyObservable(props.TextSize) or props.TextSize,
Font = Blend.toPropertyObservable(props.Font) or props.Font,
FontFace = Blend.toPropertyObservable(props.FontFace) or props.FontFace,
MaxSize = Blend.toPropertyObservable(props.MaxSize) or props.MaxSize or Vector2.new(1e6, 1e6),
LineHeight = Blend.toPropertyObservable(props.LineHeight) or 1,
}):Pipe({
Rx.switchMap(function(state)
if typeof(state.FontFace) == "Font" then
-- Yes, our font may have to stream in
local params = Instance.new("GetTextBoundsParams")
params.Text = state.Text
params.Size = state.TextSize
params.Font = state.FontFace
params.Width = state.MaxSize.x
return Rx.fromPromise(TextServiceUtils.promiseTextBounds(params))
elseif typeof(state.Font) == "EnumItem" then
local size = TextService:GetTextSize(state.Text, state.TextSize, state.Font, state.MaxSize)
return Rx.of(Vector2.new(size.x, state.LineHeight*size.y))
else
warn("[TextServiceUtils.observeSizeForLabelProps] - Got neither FontFace or Font")
return Rx.of(Vector2.zero)
end
end)
})
end
return TextServiceUtils