@effindomv2/fui-as 0.1.12 → 0.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/Fui.ts +4 -0
- package/src/controls/Checkbox.ts +29 -4
- package/src/controls/ControlSizing.ts +158 -0
- package/src/controls/Dropdown.ts +87 -20
- package/src/controls/RadioButton.ts +29 -4
- package/src/controls/Slider.ts +31 -5
- package/src/controls/index.ts +1 -0
- package/src/controls/internal/CheckboxIndicatorPresenter.ts +45 -8
- package/src/controls/internal/DropdownChevronPresenter.ts +32 -5
- package/src/controls/internal/DropdownFieldPresenter.ts +69 -8
- package/src/controls/internal/DropdownOptionRowPresenter.ts +34 -7
- package/src/controls/internal/PressableLabeledControl.ts +10 -1
- package/src/controls/internal/RadioIndicatorPresenter.ts +59 -13
- package/src/controls/internal/SliderPresenter.ts +62 -22
- package/src/controls/templating.ts +1 -0
- package/src/nodes/Text.ts +6 -0
- package/src/nodes/TextCore.ts +36 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { BorderStyle, Orientation, Unit } from "../../core/ffi";
|
|
2
2
|
import { Theme } from "../../core/Theme";
|
|
3
3
|
import { FlexBox } from "../../nodes";
|
|
4
|
+
import { SliderSizing } from "../ControlSizing";
|
|
4
5
|
|
|
5
6
|
function clamp(value: f32, min: f32, max: f32): f32 {
|
|
6
7
|
if (value < min) {
|
|
@@ -12,6 +13,18 @@ function clamp(value: f32, min: f32, max: f32): f32 {
|
|
|
12
13
|
return value;
|
|
13
14
|
}
|
|
14
15
|
|
|
16
|
+
function resolveThumbSize(metrics: SliderPresenterMetrics): f32 {
|
|
17
|
+
return metrics.thumbSize > 1.0 ? metrics.thumbSize : 1.0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function resolveTrackThickness(metrics: SliderPresenterMetrics): f32 {
|
|
21
|
+
return clamp(metrics.trackThickness, 1.0, resolveThumbSize(metrics));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function resolveCrossAxisExtra(metrics: SliderPresenterMetrics): f32 {
|
|
25
|
+
return metrics.crossAxisExtra > 0.0 ? metrics.crossAxisExtra : 0.0;
|
|
26
|
+
}
|
|
27
|
+
|
|
15
28
|
export class SliderPresenterMetrics {
|
|
16
29
|
constructor(
|
|
17
30
|
readonly thumbSize: f32,
|
|
@@ -20,6 +33,20 @@ export class SliderPresenterMetrics {
|
|
|
20
33
|
) {}
|
|
21
34
|
}
|
|
22
35
|
|
|
36
|
+
const DEFAULT_SLIDER_METRICS = new SliderPresenterMetrics(18.0, 6.0, 2.0);
|
|
37
|
+
|
|
38
|
+
function resolveSliderMetrics(sizing: SliderSizing | null): SliderPresenterMetrics {
|
|
39
|
+
if (sizing === null) {
|
|
40
|
+
return DEFAULT_SLIDER_METRICS;
|
|
41
|
+
}
|
|
42
|
+
const thumbSize = sizing.hasThumbSize ? sizing.thumbSizePx : DEFAULT_SLIDER_METRICS.thumbSize;
|
|
43
|
+
const trackThickness = sizing.hasTrackThickness ? sizing.trackThicknessPx : DEFAULT_SLIDER_METRICS.trackThickness;
|
|
44
|
+
if (thumbSize == DEFAULT_SLIDER_METRICS.thumbSize && trackThickness == DEFAULT_SLIDER_METRICS.trackThickness) {
|
|
45
|
+
return DEFAULT_SLIDER_METRICS;
|
|
46
|
+
}
|
|
47
|
+
return new SliderPresenterMetrics(thumbSize, trackThickness, DEFAULT_SLIDER_METRICS.crossAxisExtra);
|
|
48
|
+
}
|
|
49
|
+
|
|
23
50
|
export class SliderVisualState {
|
|
24
51
|
constructor(
|
|
25
52
|
readonly value: f32,
|
|
@@ -61,15 +88,15 @@ class DefaultSliderPresenter extends SliderPresenter {
|
|
|
61
88
|
private readonly fillNode: FlexBox;
|
|
62
89
|
private readonly thumbNode: FlexBox;
|
|
63
90
|
|
|
64
|
-
constructor() {
|
|
91
|
+
constructor(metrics: SliderPresenterMetrics = DEFAULT_SLIDER_METRICS) {
|
|
65
92
|
const root = new FlexBox();
|
|
66
|
-
super(root,
|
|
93
|
+
super(root, metrics);
|
|
67
94
|
const trackNode = new FlexBox().positionAbsolute();
|
|
68
95
|
const fillNode = new FlexBox().positionAbsolute();
|
|
69
96
|
const thumbNode = new FlexBox()
|
|
70
97
|
.positionAbsolute()
|
|
71
|
-
.width(
|
|
72
|
-
.height(
|
|
98
|
+
.width(metrics.thumbSize, Unit.Pixel)
|
|
99
|
+
.height(metrics.thumbSize, Unit.Pixel);
|
|
73
100
|
this.trackNode = trackNode;
|
|
74
101
|
this.fillNode = fillNode;
|
|
75
102
|
this.thumbNode = thumbNode;
|
|
@@ -81,26 +108,30 @@ class DefaultSliderPresenter extends SliderPresenter {
|
|
|
81
108
|
|
|
82
109
|
layout(state: SliderVisualState, length: f32): void {
|
|
83
110
|
const metrics = this.metrics;
|
|
84
|
-
const
|
|
111
|
+
const thumbSize = resolveThumbSize(metrics);
|
|
112
|
+
const trackThickness = resolveTrackThickness(metrics);
|
|
113
|
+
const crossAxisExtra = resolveCrossAxisExtra(metrics);
|
|
114
|
+
const available = length > thumbSize ? length - thumbSize : 0.0;
|
|
85
115
|
const fraction = clamp(state.normalizedValue, 0.0, 1.0);
|
|
86
|
-
const crossAxisInset =
|
|
116
|
+
const crossAxisInset = crossAxisExtra * 0.5;
|
|
117
|
+
const trackOffset = crossAxisInset + ((thumbSize - trackThickness) * 0.5);
|
|
87
118
|
if (state.orientation == Orientation.Vertical) {
|
|
88
119
|
this.root
|
|
89
|
-
.width(
|
|
120
|
+
.width(thumbSize + crossAxisExtra, Unit.Pixel)
|
|
90
121
|
.height(length, Unit.Pixel);
|
|
91
122
|
this.trackNode
|
|
92
|
-
.width(
|
|
123
|
+
.width(trackThickness, Unit.Pixel)
|
|
93
124
|
.height(available, Unit.Pixel)
|
|
94
125
|
.position(
|
|
95
|
-
|
|
96
|
-
|
|
126
|
+
trackOffset,
|
|
127
|
+
thumbSize * 0.5,
|
|
97
128
|
);
|
|
98
129
|
this.fillNode
|
|
99
|
-
.width(
|
|
130
|
+
.width(trackThickness, Unit.Pixel)
|
|
100
131
|
.height(available * fraction, Unit.Pixel)
|
|
101
132
|
.position(
|
|
102
|
-
|
|
103
|
-
|
|
133
|
+
trackOffset,
|
|
134
|
+
thumbSize * 0.5 + (available * (1.0 - fraction)),
|
|
104
135
|
);
|
|
105
136
|
this.thumbNode.position(
|
|
106
137
|
crossAxisInset,
|
|
@@ -111,20 +142,20 @@ class DefaultSliderPresenter extends SliderPresenter {
|
|
|
111
142
|
|
|
112
143
|
this.root
|
|
113
144
|
.width(length, Unit.Pixel)
|
|
114
|
-
.height(
|
|
145
|
+
.height(thumbSize + crossAxisExtra, Unit.Pixel);
|
|
115
146
|
this.trackNode
|
|
116
147
|
.width(available, Unit.Pixel)
|
|
117
|
-
.height(
|
|
148
|
+
.height(trackThickness, Unit.Pixel)
|
|
118
149
|
.position(
|
|
119
|
-
|
|
120
|
-
|
|
150
|
+
thumbSize * 0.5,
|
|
151
|
+
trackOffset,
|
|
121
152
|
);
|
|
122
153
|
this.fillNode
|
|
123
154
|
.width(available * fraction, Unit.Pixel)
|
|
124
|
-
.height(
|
|
155
|
+
.height(trackThickness, Unit.Pixel)
|
|
125
156
|
.position(
|
|
126
|
-
|
|
127
|
-
|
|
157
|
+
thumbSize * 0.5,
|
|
158
|
+
trackOffset,
|
|
128
159
|
);
|
|
129
160
|
this.thumbNode.position(
|
|
130
161
|
available * fraction,
|
|
@@ -137,12 +168,17 @@ class DefaultSliderPresenter extends SliderPresenter {
|
|
|
137
168
|
? theme.colors.accentPressed
|
|
138
169
|
: (state.hovered ? theme.colors.accentHovered : theme.colors.accent);
|
|
139
170
|
const metrics = this.metrics;
|
|
140
|
-
const
|
|
171
|
+
const thumbSize = resolveThumbSize(metrics);
|
|
172
|
+
const trackThickness = resolveTrackThickness(metrics);
|
|
173
|
+
const trackRadius = trackThickness * 0.5;
|
|
141
174
|
this.trackNode.cornerRadius(trackRadius);
|
|
142
175
|
this.trackNode.bgColor(theme.colors.scrollbarTrack);
|
|
143
176
|
this.fillNode.cornerRadius(trackRadius);
|
|
144
177
|
this.fillNode.bgColor(accent);
|
|
145
|
-
this.thumbNode
|
|
178
|
+
this.thumbNode
|
|
179
|
+
.width(thumbSize, Unit.Pixel)
|
|
180
|
+
.height(thumbSize, Unit.Pixel)
|
|
181
|
+
.cornerRadius(thumbSize * 0.5);
|
|
146
182
|
this.thumbNode.bgColor(accent);
|
|
147
183
|
this.thumbNode.border(1.0, theme.colors.surface, BorderStyle.Solid);
|
|
148
184
|
}
|
|
@@ -155,3 +191,7 @@ class DefaultSliderTemplate extends SliderTemplate {
|
|
|
155
191
|
}
|
|
156
192
|
|
|
157
193
|
export const defaultSliderTemplate = new DefaultSliderTemplate();
|
|
194
|
+
|
|
195
|
+
export function createDefaultSliderPresenter(sizing: SliderSizing | null = null): SliderPresenter {
|
|
196
|
+
return new DefaultSliderPresenter(resolveSliderMetrics(sizing));
|
|
197
|
+
}
|
package/src/nodes/Text.ts
CHANGED
|
@@ -15,9 +15,15 @@ export class Text extends TextCore {
|
|
|
15
15
|
if (props.hasWidth) {
|
|
16
16
|
text.width(props.widthValue, props.widthUnit);
|
|
17
17
|
}
|
|
18
|
+
if (props.hasFillWidth) {
|
|
19
|
+
text.fillWidth();
|
|
20
|
+
}
|
|
18
21
|
if (props.hasHeight) {
|
|
19
22
|
text.height(props.heightValue, props.heightUnit);
|
|
20
23
|
}
|
|
24
|
+
if (props.hasFillHeight) {
|
|
25
|
+
text.fillHeight();
|
|
26
|
+
}
|
|
21
27
|
if (props.hasFontFamily) {
|
|
22
28
|
const family = props.fontFamilyValue;
|
|
23
29
|
if (family !== null) {
|
package/src/nodes/TextCore.ts
CHANGED
|
@@ -20,9 +20,11 @@ export class TextProps {
|
|
|
20
20
|
widthValue: f32 = 0.0;
|
|
21
21
|
widthUnit: Unit = Unit.Pixel;
|
|
22
22
|
hasWidth: bool = false;
|
|
23
|
+
hasFillWidth: bool = false;
|
|
23
24
|
heightValue: f32 = 0.0;
|
|
24
25
|
heightUnit: Unit = Unit.Pixel;
|
|
25
26
|
hasHeight: bool = false;
|
|
27
|
+
hasFillHeight: bool = false;
|
|
26
28
|
fontId: u32 = 0;
|
|
27
29
|
fontSize: f32 = 0.0;
|
|
28
30
|
hasFont: bool = false;
|
|
@@ -66,9 +68,11 @@ export class TextCore extends Node {
|
|
|
66
68
|
private widthValue: f32 = 0.0;
|
|
67
69
|
private widthUnit: Unit = Unit.Pixel;
|
|
68
70
|
private hasWidth: bool = false;
|
|
71
|
+
private hasFillWidth: bool = false;
|
|
69
72
|
private heightValue: f32 = 0.0;
|
|
70
73
|
private heightUnit: Unit = Unit.Pixel;
|
|
71
74
|
private hasHeight: bool = false;
|
|
75
|
+
private hasFillHeight: bool = false;
|
|
72
76
|
private fontId: u32 = 0;
|
|
73
77
|
private fontSizeValue: f32 = 0.0;
|
|
74
78
|
private hasFont: bool = false;
|
|
@@ -147,6 +151,7 @@ export class TextCore extends Node {
|
|
|
147
151
|
this.widthValue = value;
|
|
148
152
|
this.widthUnit = unit;
|
|
149
153
|
this.hasWidth = true;
|
|
154
|
+
this.hasFillWidth = false;
|
|
150
155
|
if (this.hasBuiltHandle()) {
|
|
151
156
|
ui.setWidth(this.handle, value, <u32>unit);
|
|
152
157
|
this.notifyRetainedLayoutMutation();
|
|
@@ -158,6 +163,7 @@ export class TextCore extends Node {
|
|
|
158
163
|
this.heightValue = value;
|
|
159
164
|
this.heightUnit = unit;
|
|
160
165
|
this.hasHeight = true;
|
|
166
|
+
this.hasFillHeight = false;
|
|
161
167
|
if (this.hasBuiltHandle()) {
|
|
162
168
|
ui.setHeight(this.handle, value, <u32>unit);
|
|
163
169
|
this.notifyRetainedLayoutMutation();
|
|
@@ -165,6 +171,30 @@ export class TextCore extends Node {
|
|
|
165
171
|
return this;
|
|
166
172
|
}
|
|
167
173
|
|
|
174
|
+
fillWidth(): this {
|
|
175
|
+
this.hasFillWidth = true;
|
|
176
|
+
if (this.hasBuiltHandle()) {
|
|
177
|
+
ui.setFillWidth(this.handle, true);
|
|
178
|
+
this.notifyRetainedLayoutMutation();
|
|
179
|
+
}
|
|
180
|
+
return this;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
fillHeight(): this {
|
|
184
|
+
this.hasFillHeight = true;
|
|
185
|
+
if (this.hasBuiltHandle()) {
|
|
186
|
+
ui.setFillHeight(this.handle, true);
|
|
187
|
+
this.notifyRetainedLayoutMutation();
|
|
188
|
+
}
|
|
189
|
+
return this;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
fillSize(): this {
|
|
193
|
+
this.fillWidth();
|
|
194
|
+
this.fillHeight();
|
|
195
|
+
return this;
|
|
196
|
+
}
|
|
197
|
+
|
|
168
198
|
text(content: string): this {
|
|
169
199
|
this.contentValue = content;
|
|
170
200
|
if (this.hasBuiltHandle()) {
|
|
@@ -423,9 +453,15 @@ export class TextCore extends Node {
|
|
|
423
453
|
if (this.hasWidth) {
|
|
424
454
|
ui.setWidth(this.handle, this.widthValue, <u32>this.widthUnit);
|
|
425
455
|
}
|
|
456
|
+
if (this.hasFillWidth) {
|
|
457
|
+
ui.setFillWidth(this.handle, true);
|
|
458
|
+
}
|
|
426
459
|
if (this.hasHeight) {
|
|
427
460
|
ui.setHeight(this.handle, this.heightValue, <u32>this.heightUnit);
|
|
428
461
|
}
|
|
462
|
+
if (this.hasFillHeight) {
|
|
463
|
+
ui.setFillHeight(this.handle, true);
|
|
464
|
+
}
|
|
429
465
|
ui.setText(this.handle, this.contentValue);
|
|
430
466
|
if (this.textStyleRunsWords !== null) {
|
|
431
467
|
ui.setTextStyleRuns(this.handle, changetype<Uint32Array>(this.textStyleRunsWords));
|