@effindomv2/fui-as 0.1.37 → 0.1.41

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.
Files changed (119) hide show
  1. package/browser/routed-app-conventions.ts +1 -1
  2. package/browser/src/common-harness.ts +1 -27
  3. package/browser/src/index.ts +19 -26
  4. package/browser/src/routed-harness.ts +1 -194
  5. package/browser/src/shared-browser.ts +3 -0
  6. package/package.json +23 -13
  7. package/scripts/build.sh +70 -46
  8. package/scripts/check-runtime-dependency.sh +0 -19
  9. package/scripts/framework-host-services.ts +1 -1
  10. package/scripts/generate-host-events.ts +15 -241
  11. package/scripts/generate-host-services.ts +13 -261
  12. package/scripts/hostgen/assemblyscript-host-events.ts +165 -0
  13. package/scripts/hostgen/assemblyscript-host-services.ts +207 -0
  14. package/scripts/hostgen/common.ts +73 -0
  15. package/scripts/hostgen/registry.ts +159 -0
  16. package/src/Fui.ts +65 -5
  17. package/src/FuiExports.ts +12 -1
  18. package/src/bindings/ui.ts +157 -8
  19. package/src/controls/Button.ts +98 -71
  20. package/src/controls/Checkbox.ts +23 -21
  21. package/src/controls/ComboBox.ts +1201 -0
  22. package/src/controls/ContextMenu.ts +279 -165
  23. package/src/controls/Dialog.ts +91 -17
  24. package/src/controls/Dropdown.ts +101 -333
  25. package/src/controls/NavLink.ts +29 -6
  26. package/src/controls/Popup.ts +10 -5
  27. package/src/controls/ProgressBar.ts +1 -2
  28. package/src/controls/RadioButton.ts +34 -13
  29. package/src/controls/RadioGroup.ts +32 -19
  30. package/src/controls/Slider.ts +21 -23
  31. package/src/controls/Switch.ts +34 -17
  32. package/src/controls/index.ts +2 -1
  33. package/src/controls/internal/ButtonPresenter.ts +5 -2
  34. package/src/controls/internal/CheckboxIndicatorPresenter.ts +10 -10
  35. package/src/controls/internal/DropdownChevronPresenter.ts +3 -3
  36. package/src/controls/internal/DropdownFieldPresenter.ts +6 -6
  37. package/src/controls/internal/DropdownOptionRowPresenter.ts +5 -4
  38. package/src/controls/internal/PressableLabeledControl.ts +4 -7
  39. package/src/controls/internal/RadioIndicatorPresenter.ts +7 -7
  40. package/src/controls/internal/SelectablePopupList.ts +463 -0
  41. package/src/controls/internal/SliderPresenter.ts +5 -5
  42. package/src/controls/internal/SwitchIndicatorPresenter.ts +63 -17
  43. package/src/controls/internal/TextInputCore.ts +307 -41
  44. package/src/controls/internal/TextInputPresenter.ts +2 -2
  45. package/src/controls/templating.ts +10 -0
  46. package/src/core/Application.ts +17 -8
  47. package/src/core/Bitmap.ts +192 -3
  48. package/src/core/ContextMenuManager.ts +128 -44
  49. package/src/core/DebugApi.ts +17 -2
  50. package/src/core/DragGesture.ts +8 -7
  51. package/src/core/EventRouter.ts +332 -12
  52. package/src/core/Fetch.ts +15 -7
  53. package/src/core/FetchFfi.ts +1 -15
  54. package/src/core/File.ts +75 -34
  55. package/src/core/FocusAdornerManager.ts +3 -3
  56. package/src/core/FocusVisibility.ts +7 -0
  57. package/src/core/FrameScheduler.ts +104 -5
  58. package/src/core/ImageSampling.ts +43 -0
  59. package/src/core/Logger.ts +2 -0
  60. package/src/core/MobileTextSelectionToolbarManager.ts +901 -0
  61. package/src/core/Node.ts +1039 -97
  62. package/src/core/Platform.ts +16 -16
  63. package/src/core/SelectionHandleAdornerManager.ts +697 -0
  64. package/src/core/Theme.ts +34 -20
  65. package/src/core/ToolTipManager.ts +3 -3
  66. package/src/core/Typography.ts +411 -19
  67. package/src/core/Worker.ts +69 -33
  68. package/src/core/event_exports.ts +123 -5
  69. package/src/core/ffi.ts +5 -865
  70. package/src/core/generated/FetchHostAbi.ts +10 -0
  71. package/src/core/generated/FrameworkHostServices.ts +1 -1
  72. package/src/core/generated/HostAbi.ts +220 -0
  73. package/src/core/generated/UiAbi.ts +356 -0
  74. package/src/core/generated/UiEnums.ts +186 -0
  75. package/src/drawing/DrawCallback.ts +17 -1
  76. package/src/drawing/DrawContext.ts +140 -32
  77. package/src/nodes/CustomDrawable.ts +8 -1
  78. package/src/nodes/FlexBox.ts +40 -11
  79. package/src/nodes/Grid.ts +5 -5
  80. package/src/nodes/Image.ts +20 -1
  81. package/src/nodes/RichText.ts +36 -25
  82. package/src/nodes/ScrollBar.ts +2 -1
  83. package/src/nodes/ScrollBox.ts +7 -2
  84. package/src/nodes/ScrollView.ts +17 -6
  85. package/src/nodes/Svg.ts +18 -1
  86. package/src/nodes/Text.ts +1 -1
  87. package/src/nodes/TextCore.ts +115 -20
  88. package/src/nodes/index.ts +1 -1
  89. package/src/text/DynamicTextLayout.ts +275 -0
  90. package/src/text/TextLayout.ts +308 -0
  91. package/src/worker/Worker.ts +3 -36
  92. package/src/worker/WorkerJob.ts +5 -9
  93. package/src/worker/ffi.ts +0 -6
  94. package/browser/src/common-harness/host-imports.ts +0 -447
  95. package/browser/src/common-harness/interop.ts +0 -39
  96. package/browser/src/common-harness/managed-harness-bitmap-host.ts +0 -92
  97. package/browser/src/common-harness/managed-harness-canvas-host.ts +0 -72
  98. package/browser/src/common-harness/managed-harness-fetch-host.ts +0 -201
  99. package/browser/src/common-harness/managed-harness-file-host.ts +0 -1066
  100. package/browser/src/common-harness/managed-harness-file-payloads.ts +0 -143
  101. package/browser/src/common-harness/managed-harness-file-types.ts +0 -71
  102. package/browser/src/common-harness/managed-harness-session.ts +0 -15
  103. package/browser/src/common-harness/managed-harness.ts +0 -1472
  104. package/browser/src/common-harness/managed-history.ts +0 -168
  105. package/browser/src/common-harness/persisted-restore-policy.ts +0 -50
  106. package/browser/src/common-harness/persisted-ui-state-controller.ts +0 -309
  107. package/browser/src/common-harness/text-session-bridge.ts +0 -452
  108. package/browser/src/common-harness/types.ts +0 -206
  109. package/browser/src/common-harness/ui-chrome.ts +0 -206
  110. package/browser/src/common-harness/ui-imports.ts +0 -559
  111. package/browser/src/common-harness/wasm-module-cache.ts +0 -47
  112. package/browser/src/file-processing-worker.ts +0 -89
  113. package/browser/src/host-events.ts +0 -118
  114. package/browser/src/host-services.ts +0 -483
  115. package/browser/src/persisted-ui-state.ts +0 -206
  116. package/browser/src/routed-app-conventions.ts +0 -292
  117. package/browser/src/worker-bootstrap.ts +0 -916
  118. package/browser/src/worker-manager.ts +0 -234
  119. package/browser/src/worker-types.ts +0 -68
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  CursorStyle,
3
3
  KeyEventType,
4
+ KeyModifier,
4
5
  PointerEventType,
5
6
  SemanticRole,
6
7
  fui_hide_url_preview,
@@ -11,16 +12,25 @@ import { Disposable, disposeAll } from "../core/Disposable";
11
12
  import { FocusAdornerManager } from "../core/FocusAdornerManager";
12
13
  import { keyboardFocusVisible } from "../core/FocusVisibility";
13
14
  import { navigateTo } from "../core/Navigation";
15
+ import { PointerEventArgs, PointerType } from "../core/Node";
14
16
  import { hasPrimaryShortcutModifier } from "../core/Platform";
15
17
  import { Theme, activeTheme } from "../core/Theme";
16
18
  import { FlexBox } from "../nodes";
17
19
 
20
+ export class NavigateEventArgs {
21
+ readonly path: string;
22
+
23
+ constructor(path: string) {
24
+ this.path = path;
25
+ }
26
+ }
27
+
18
28
  export class NavLink extends FlexBox {
19
29
  private static activePreviewOwner: NavLink | null = null;
20
30
  private hrefValue: string;
21
31
  private openInNewTabValue: bool;
22
32
  private readonly disposables: Array<Disposable> = new Array<Disposable>();
23
- private navigateCallback: ((path: string) => void) | null = null;
33
+ private navigateCallback: ((event: NavigateEventArgs) => void) | null = null;
24
34
  private pointerPressed: bool = false;
25
35
  private pointerPressedOpenInNewTab: bool = false;
26
36
  private enterPressed: bool = false;
@@ -60,7 +70,7 @@ export class NavLink extends FlexBox {
60
70
  return this;
61
71
  }
62
72
 
63
- onNavigate(cb: (path: string) => void): this {
73
+ onNavigate(cb: (event: NavigateEventArgs) => void): this {
64
74
  this.navigateCallback = cb;
65
75
  return this;
66
76
  }
@@ -75,6 +85,10 @@ export class NavLink extends FlexBox {
75
85
  }
76
86
 
77
87
  _handlePointerEvent(eventType: PointerEventType, x: f32, y: f32, modifiers: u32 = 0): void {
88
+ const pending = NavLink.pendingPointerEventArgs;
89
+ const isPrimaryActivation = pending !== null
90
+ ? this.isPrimaryActivationPointer(changetype<PointerEventArgs>(pending))
91
+ : true;
78
92
  super._handlePointerEvent(eventType, x, y, modifiers);
79
93
  if (eventType == PointerEventType.Enter) {
80
94
  this.hovered = true;
@@ -91,11 +105,16 @@ export class NavLink extends FlexBox {
91
105
  return;
92
106
  }
93
107
  if (eventType == PointerEventType.Down) {
108
+ if (!isPrimaryActivation) {
109
+ this.pointerPressed = false;
110
+ this.pointerPressedOpenInNewTab = false;
111
+ return;
112
+ }
94
113
  this.pointerPressed = true;
95
114
  this.pointerPressedOpenInNewTab = this.shouldOpenInNewTab(modifiers);
96
115
  return;
97
116
  }
98
- if (eventType == PointerEventType.Up && this.pointerPressed) {
117
+ if (eventType == PointerEventType.Up && this.pointerPressed && isPrimaryActivation) {
99
118
  this.pointerPressed = false;
100
119
  this.activate(this.pointerPressedOpenInNewTab || this.shouldOpenInNewTab(modifiers));
101
120
  this.pointerPressedOpenInNewTab = false;
@@ -123,7 +142,7 @@ export class NavLink extends FlexBox {
123
142
  if (key != "Enter") {
124
143
  return callbackHandled;
125
144
  }
126
- if (modifiers != 0 && !hasPrimaryShortcutModifier(modifiers)) {
145
+ if (modifiers != 0 && !hasPrimaryShortcutModifier(<KeyModifier>modifiers)) {
127
146
  return callbackHandled;
128
147
  }
129
148
  if (eventType == KeyEventType.Down) {
@@ -144,12 +163,16 @@ export class NavLink extends FlexBox {
144
163
  navigateTo(this.hrefValue, openInNewTab);
145
164
  const callback = this.navigateCallback;
146
165
  if (callback !== null) {
147
- callback(this.hrefValue);
166
+ callback(new NavigateEventArgs(this.hrefValue));
148
167
  }
149
168
  }
150
169
 
151
170
  private shouldOpenInNewTab(modifiers: u32): bool {
152
- return this.openInNewTabValue || hasPrimaryShortcutModifier(modifiers);
171
+ return this.openInNewTabValue || hasPrimaryShortcutModifier(<KeyModifier>modifiers);
172
+ }
173
+
174
+ private isPrimaryActivationPointer(event: PointerEventArgs): bool {
175
+ return event.button == 0 || event.pointerType == PointerType.Touch || event.pointerType == PointerType.Pen;
153
176
  }
154
177
 
155
178
  pinPreviewForContextMenu(): void {
@@ -1,7 +1,7 @@
1
- import { BorderStyle, FlexDirection, Unit } from "../core/ffi";
1
+ import { FlexDirection, Unit } from "../core/ffi";
2
2
  import { Node } from "../core/Node";
3
3
  import { throwNullArgument } from "../core/Errors";
4
- import { FlexBox, Portal } from "../nodes";
4
+ import { Border, FlexBox, Portal } from "../nodes";
5
5
  import { PopupPlacement, PopupPresenter } from "./internal/PopupPresenter";
6
6
 
7
7
  export { PopupPlacement } from "./internal/PopupPresenter";
@@ -21,7 +21,7 @@ export class Popup extends Portal {
21
21
  .position(0.0, 0.0)
22
22
  .width(100.0, Unit.Percent)
23
23
  .height(100.0, Unit.Percent);
24
- this.presenter.overlayNode.onClickWith(this, (popup) => popup.handleBackdropClick());
24
+ this.presenter.overlayNode.onPointerClickWith(this, (popup, _event) => popup.handleBackdropClick());
25
25
  }
26
26
 
27
27
  get isOpen(): bool {
@@ -90,8 +90,13 @@ export class Popup extends Portal {
90
90
  return this;
91
91
  }
92
92
 
93
- panelBorder(width: f32, color: u32, style: BorderStyle = BorderStyle.Solid): this {
94
- this.surfaceNode.border(width, color, style);
93
+ panelBorder(width: f32, color: u32): this {
94
+ this.surfaceNode.border(width, color);
95
+ return this;
96
+ }
97
+
98
+ panelBorderConfig(border: Border): this {
99
+ this.surfaceNode.borderConfig(border);
95
100
  return this;
96
101
  }
97
102
 
@@ -1,4 +1,3 @@
1
- import { BorderStyle } from "../core/ffi";
2
1
  import { HandlerAction } from "../core/Action";
3
2
  import { Disposable, disposeAll } from "../core/Disposable";
4
3
  import { Theme, activeTheme } from "../core/Theme";
@@ -154,7 +153,7 @@ export class ProgressBar extends FlexBox {
154
153
  this.fillNode.cornerRadius(this.thicknessValue * 0.5);
155
154
  }
156
155
  super.bgColor(trackColor);
157
- super.border(1.0, theme.colors.border, BorderStyle.Solid);
156
+ super.border(1.0, theme.colors.border);
158
157
  this.fillNode.bgColor(fillColor);
159
158
  }
160
159
 
@@ -1,5 +1,8 @@
1
+ import { Callback1, Handler1 } from "../core/BoundCallback";
1
2
  import { KeyEventType, SemanticCheckedState, SemanticRole } from "../core/ffi";
3
+ import { RadioButtonChangedEventArgs } from "../core/Node";
2
4
  import { activeTheme } from "../core/Theme";
5
+ import { bind1 } from "../core/bind";
3
6
  import { LabeledControlSizing } from "./ControlSizing";
4
7
  import { PressableLabeledControl } from "./internal/PressableLabeledControl";
5
8
  import { getControlTemplates } from "./ControlTemplateSet";
@@ -13,13 +16,13 @@ import {
13
16
 
14
17
  function createIndicatorPresenter(template: RadioIndicatorTemplate | null, sizing: LabeledControlSizing | null = null): RadioIndicatorPresenter {
15
18
  if (template !== null) {
16
- return template.create();
19
+ return template.create(sizing);
17
20
  }
18
21
  const templateSet = getControlTemplates();
19
22
  const appTemplate = templateSet !== null ? templateSet.radioIndicator : null;
20
23
  return appTemplate === null
21
24
  ? createDefaultRadioIndicatorPresenter(sizing)
22
- : appTemplate.create();
25
+ : appTemplate.create(sizing);
23
26
  }
24
27
 
25
28
  export class RadioButton extends PressableLabeledControl {
@@ -28,7 +31,8 @@ export class RadioButton extends PressableLabeledControl {
28
31
  private sizingValue: LabeledControlSizing | null = null;
29
32
  private readonly valueText: string;
30
33
  private checkedValue: bool = false;
31
- private changedCallback: ((checked: bool) => void) | null = null;
34
+ private changedCallback: ((event: RadioButtonChangedEventArgs) => void) | null = null;
35
+ private changedBinding: Callback1<RadioButtonChangedEventArgs> | null = null;
32
36
  private ownerGroup: RadioGroup | null = null;
33
37
 
34
38
  constructor(value: string, label: string = value) {
@@ -54,7 +58,7 @@ export class RadioButton extends PressableLabeledControl {
54
58
  }
55
59
 
56
60
  check(flag: bool): this {
57
- this.updateChecked(flag, false);
61
+ this.updateChecked(flag, true, false);
58
62
  return this;
59
63
  }
60
64
 
@@ -63,11 +67,9 @@ export class RadioButton extends PressableLabeledControl {
63
67
  this.setLabelFontSizeOverride(
64
68
  sizing !== null && sizing.hasLabelFontSize ? sizing.labelFontSizePx : 0.0,
65
69
  );
66
- if (this.usesDefaultIndicatorPresenter()) {
67
- this.indicatorPresenter = createIndicatorPresenter(this.templateOverride, this.sizingValue);
68
- this.replaceIndicatorRoot(this.indicatorPresenter.root);
69
- this.syncVisualState();
70
- }
70
+ this.indicatorPresenter = createIndicatorPresenter(this.templateOverride, this.sizingValue);
71
+ this.replaceIndicatorRoot(this.indicatorPresenter.root);
72
+ this.syncVisualState();
71
73
  return this;
72
74
  }
73
75
 
@@ -79,8 +81,20 @@ export class RadioButton extends PressableLabeledControl {
79
81
  return this;
80
82
  }
81
83
 
82
- onChanged(callback: ((checked: bool) => void) | null): this {
84
+ onChanged(callback: ((event: RadioButtonChangedEventArgs) => void) | null): this {
83
85
  this.changedCallback = callback;
86
+ this.changedBinding = null;
87
+ return this;
88
+ }
89
+
90
+ bindChanged<Owner>(owner: Owner, handler: Handler1<Owner, RadioButtonChangedEventArgs>): this {
91
+ this.changedCallback = null;
92
+ this.changedBinding = bind1<Owner, RadioButtonChangedEventArgs>(owner, handler);
93
+ return this;
94
+ }
95
+
96
+ onChangedWith<Owner>(owner: Owner, handler: Handler1<Owner, RadioButtonChangedEventArgs>): this {
97
+ this.bindChanged(owner, handler);
84
98
  return this;
85
99
  }
86
100
 
@@ -135,7 +149,7 @@ export class RadioButton extends PressableLabeledControl {
135
149
  );
136
150
  }
137
151
 
138
- updateChecked(flag: bool, emit: bool): void {
152
+ updateChecked(flag: bool, emit: bool, announce: bool = emit): void {
139
153
  if (this.checkedValue == flag) {
140
154
  return;
141
155
  }
@@ -143,10 +157,17 @@ export class RadioButton extends PressableLabeledControl {
143
157
  this.semanticChecked(flag ? SemanticCheckedState.True : SemanticCheckedState.False);
144
158
  this.syncVisualState();
145
159
  if (emit) {
146
- this.requestSemanticAnnouncement();
160
+ if (announce) {
161
+ this.requestSemanticAnnouncement();
162
+ }
163
+ const event = new RadioButtonChangedEventArgs(flag);
147
164
  const callback = this.changedCallback;
148
165
  if (callback !== null) {
149
- callback(flag);
166
+ callback(event);
167
+ }
168
+ const binding = this.changedBinding;
169
+ if (binding !== null) {
170
+ binding.invoke(event);
150
171
  }
151
172
  }
152
173
  }
@@ -1,5 +1,6 @@
1
1
  import { Callback1, Handler1 } from "../core/BoundCallback";
2
2
  import { FlexDirection, SemanticRole } from "../core/ffi";
3
+ import { RadioGroupChangedEventArgs } from "../core/Node";
3
4
  import { PersistedInt32Codec, PersistedValueState } from "../core/PersistedState";
4
5
  import { bind1 } from "../core/bind";
5
6
  import { warn } from "../core/Logger";
@@ -31,8 +32,8 @@ const RADIO_GROUP_PERSISTED_STATE = new PersistedRadioGroupState();
31
32
  export class RadioGroup extends FlexBox {
32
33
  private readonly radios: Array<RadioButton> = new Array<RadioButton>();
33
34
  private selectedIndexValue: i32 = -1;
34
- private changedCallback: ((value: string) => void) | null = null;
35
- private changedBinding: Callback1<string> | null = null;
35
+ private changedCallback: ((event: RadioGroupChangedEventArgs) => void) | null = null;
36
+ private changedBinding: Callback1<RadioGroupChangedEventArgs> | null = null;
36
37
 
37
38
  constructor() {
38
39
  super();
@@ -75,19 +76,19 @@ export class RadioGroup extends FlexBox {
75
76
  return this;
76
77
  }
77
78
 
78
- onChanged(callback: ((value: string) => void) | null): this {
79
+ onChanged(callback: ((event: RadioGroupChangedEventArgs) => void) | null): this {
79
80
  this.changedCallback = callback;
80
81
  this.changedBinding = null;
81
82
  return this;
82
83
  }
83
84
 
84
- bindChanged<Owner>(owner: Owner, handler: Handler1<Owner, string>): this {
85
+ bindChanged<Owner>(owner: Owner, handler: Handler1<Owner, RadioGroupChangedEventArgs>): this {
85
86
  this.changedCallback = null;
86
- this.changedBinding = bind1<Owner, string>(owner, handler);
87
+ this.changedBinding = bind1<Owner, RadioGroupChangedEventArgs>(owner, handler);
87
88
  return this;
88
89
  }
89
90
 
90
- onChangedWith<Owner>(owner: Owner, handler: Handler1<Owner, string>): this {
91
+ onChangedWith<Owner>(owner: Owner, handler: Handler1<Owner, RadioGroupChangedEventArgs>): this {
91
92
  this.bindChanged(owner, handler);
92
93
  return this;
93
94
  }
@@ -95,7 +96,7 @@ export class RadioGroup extends FlexBox {
95
96
  selectRadio(radio: RadioButton, focus: bool): void {
96
97
  const index = this.indexOfRadio(radio);
97
98
  if (index >= 0) {
98
- this.selectIndexInternal(index, focus, true);
99
+ this.selectIndexInternal(index, focus, true, true);
99
100
  }
100
101
  }
101
102
 
@@ -106,30 +107,42 @@ export class RadioGroup extends FlexBox {
106
107
  }
107
108
  const nextIndex = this.findEnabledIndex(startIndex, delta);
108
109
  if (nextIndex >= 0) {
109
- this.selectIndexInternal(nextIndex, true, true);
110
+ this.selectIndexInternal(nextIndex, true, true, true);
110
111
  }
111
112
  }
112
113
 
113
114
  selectFirstEnabled(focus: bool): void {
114
115
  const nextIndex = this.findBoundaryIndex(true);
115
116
  if (nextIndex >= 0) {
116
- this.selectIndexInternal(nextIndex, focus, true);
117
+ this.selectIndexInternal(nextIndex, focus, true, true);
117
118
  }
118
119
  }
119
120
 
120
121
  selectLastEnabled(focus: bool): void {
121
122
  const nextIndex = this.findBoundaryIndex(false);
122
123
  if (nextIndex >= 0) {
123
- this.selectIndexInternal(nextIndex, focus, true);
124
+ this.selectIndexInternal(nextIndex, focus, true, true);
124
125
  }
125
126
  }
126
127
 
127
128
  selectIndex(index: i32): this {
128
129
  if (index == -1) {
130
+ const changed = this.selectedIndexValue != -1;
129
131
  if (this.selectedIndexValue >= 0 && this.selectedIndexValue < this.radios.length) {
130
- unchecked(this.radios[this.selectedIndexValue]).updateChecked(false, false);
132
+ unchecked(this.radios[this.selectedIndexValue]).updateChecked(false, true, false);
131
133
  }
132
134
  this.selectedIndexValue = -1;
135
+ if (changed) {
136
+ const event = new RadioGroupChangedEventArgs("");
137
+ const callback = this.changedCallback;
138
+ if (callback !== null) {
139
+ callback(event);
140
+ }
141
+ const binding = this.changedBinding;
142
+ if (binding !== null) {
143
+ binding.invoke(event);
144
+ }
145
+ }
133
146
  return this;
134
147
  }
135
148
  if (this.radios.length == 0) {
@@ -151,7 +164,7 @@ export class RadioGroup extends FlexBox {
151
164
  ".",
152
165
  );
153
166
  }
154
- this.selectIndexInternal(clampedIndex, false, false);
167
+ this.selectIndexInternal(clampedIndex, false, true, false);
155
168
  return this;
156
169
  }
157
170
 
@@ -159,10 +172,10 @@ export class RadioGroup extends FlexBox {
159
172
  if (index < 0) {
160
173
  return;
161
174
  }
162
- this.selectIndexInternal(index, false, true);
175
+ this.selectIndexInternal(index, false, true, false);
163
176
  }
164
177
 
165
- private selectIndexInternal(index: i32, focus: bool, emit: bool): void {
178
+ private selectIndexInternal(index: i32, focus: bool, emit: bool, announce: bool = emit): void {
166
179
  if (index < 0 || index >= this.radios.length) {
167
180
  return;
168
181
  }
@@ -177,22 +190,22 @@ export class RadioGroup extends FlexBox {
177
190
  return;
178
191
  }
179
192
  if (this.selectedIndexValue >= 0 && this.selectedIndexValue < this.radios.length) {
180
- unchecked(this.radios[this.selectedIndexValue]).updateChecked(false, false);
193
+ unchecked(this.radios[this.selectedIndexValue]).updateChecked(false, emit, false);
181
194
  }
182
195
  this.selectedIndexValue = index;
183
- radio.updateChecked(true, false);
196
+ radio.updateChecked(true, emit, announce);
184
197
  if (focus) {
185
198
  radio.focusNow();
186
199
  }
187
200
  if (emit) {
188
- radio.requestSemanticAnnouncement();
201
+ const event = new RadioGroupChangedEventArgs(radio.value);
189
202
  const callback = this.changedCallback;
190
203
  if (callback !== null) {
191
- callback(radio.value);
204
+ callback(event);
192
205
  }
193
206
  const binding = this.changedBinding;
194
207
  if (binding !== null) {
195
- binding.invoke(radio.value);
208
+ binding.invoke(event);
196
209
  }
197
210
  }
198
211
  }
@@ -6,7 +6,6 @@ import { DragCompletedEvent, DragDeltaEvent, DragGesture, DragGestureHost, DragS
6
6
  import { FocusAdornerManager } from "../core/FocusAdornerManager";
7
7
  import { keyboardFocusVisible } from "../core/FocusVisibility";
8
8
  import {
9
- BorderStyle,
10
9
  CursorStyle,
11
10
  KeyEventType,
12
11
  Orientation,
@@ -17,7 +16,7 @@ import {
17
16
  import { Theme, activeTheme } from "../core/Theme";
18
17
  import { warn } from "../core/Logger";
19
18
  import { PersistedFloat32Codec, PersistedValueState } from "../core/PersistedState";
20
- import { Node } from "../core/Node";
19
+ import { Node, SliderChangedEventArgs } from "../core/Node";
21
20
  import { FlexBox } from "../nodes";
22
21
  import { bind1 } from "../core/bind";
23
22
  import { SliderSizing } from "./ControlSizing";
@@ -67,13 +66,13 @@ const SLIDER_CHILD_INSET: f32 = SLIDER_PADDING + SLIDER_CONTENT_INSET;
67
66
 
68
67
  function createSliderPresenter(template: SliderTemplate | null, sizing: SliderSizing | null = null): SliderPresenter {
69
68
  if (template !== null) {
70
- return template.create();
69
+ return template.create(sizing);
71
70
  }
72
71
  const templateSet = getControlTemplates();
73
72
  const appTemplate = templateSet !== null ? templateSet.slider : null;
74
73
  return appTemplate === null
75
74
  ? createDefaultSliderPresenter(sizing)
76
- : appTemplate.create();
75
+ : appTemplate.create(sizing);
77
76
  }
78
77
 
79
78
  export class Slider extends FlexBox implements DragGestureHost {
@@ -83,8 +82,8 @@ export class Slider extends FlexBox implements DragGestureHost {
83
82
  private colorsValue: SliderColors | null = null;
84
83
  private readonly disposables: Array<Disposable> = new Array<Disposable>();
85
84
  private readonly dragGesture!: DragGesture;
86
- private changedCallback: ((value: f32) => void) | null = null;
87
- private changedBinding: Callback1<f32> | null = null;
85
+ private changedCallback: ((event: SliderChangedEventArgs) => void) | null = null;
86
+ private changedBinding: Callback1<SliderChangedEventArgs> | null = null;
88
87
  private disposed: bool = false;
89
88
  private focusedState: bool = false;
90
89
  private hoveredState: bool = false;
@@ -135,7 +134,7 @@ export class Slider extends FlexBox implements DragGestureHost {
135
134
  if (this.maxValue < value) {
136
135
  this.maxValue = value;
137
136
  }
138
- this.setValue(this.currentValue, false);
137
+ this.setValue(this.currentValue, true, false);
139
138
  return this;
140
139
  }
141
140
 
@@ -144,7 +143,7 @@ export class Slider extends FlexBox implements DragGestureHost {
144
143
  if (this.minValue > value) {
145
144
  this.minValue = value;
146
145
  }
147
- this.setValue(this.currentValue, false);
146
+ this.setValue(this.currentValue, true, false);
148
147
  return this;
149
148
  }
150
149
 
@@ -153,7 +152,7 @@ export class Slider extends FlexBox implements DragGestureHost {
153
152
  warn("Layout", "Slider.step() received " + value.toString() + "; clamping to 1.0.");
154
153
  }
155
154
  this.stepValue = value > 0.0 ? value : 1.0;
156
- this.setValue(this.currentValue, false);
155
+ this.setValue(this.currentValue, true, false);
157
156
  return this;
158
157
  }
159
158
 
@@ -180,9 +179,6 @@ export class Slider extends FlexBox implements DragGestureHost {
180
179
 
181
180
  sizing(sizing: SliderSizing | null): this {
182
181
  this.sizingValue = sizing;
183
- if (!this.usesDefaultPresenter()) {
184
- return this;
185
- }
186
182
  this.replacePresenter(createSliderPresenter(this.templateOverride, this.sizingValue));
187
183
  const thumbSize = this.sliderPresenter.metrics.thumbSize;
188
184
  if (this.lengthValue <= thumbSize) {
@@ -214,19 +210,19 @@ export class Slider extends FlexBox implements DragGestureHost {
214
210
  return this;
215
211
  }
216
212
 
217
- onChanged(callback: ((value: f32) => void) | null): this {
213
+ onChanged(callback: ((event: SliderChangedEventArgs) => void) | null): this {
218
214
  this.changedCallback = callback;
219
215
  this.changedBinding = null;
220
216
  return this;
221
217
  }
222
218
 
223
- bindChanged<Owner>(owner: Owner, handler: Handler1<Owner, f32>): this {
219
+ bindChanged<Owner>(owner: Owner, handler: Handler1<Owner, SliderChangedEventArgs>): this {
224
220
  this.changedCallback = null;
225
- this.changedBinding = bind1<Owner, f32>(owner, handler);
221
+ this.changedBinding = bind1<Owner, SliderChangedEventArgs>(owner, handler);
226
222
  return this;
227
223
  }
228
224
 
229
- onChangedWith<Owner>(owner: Owner, handler: Handler1<Owner, f32>): this {
225
+ onChangedWith<Owner>(owner: Owner, handler: Handler1<Owner, SliderChangedEventArgs>): this {
230
226
  this.bindChanged(owner, handler);
231
227
  return this;
232
228
  }
@@ -322,7 +318,7 @@ export class Slider extends FlexBox implements DragGestureHost {
322
318
  }
323
319
 
324
320
  _applyPersistedValue(value: f32): void {
325
- this.setValue(value, true);
321
+ this.setValue(value, true, false);
326
322
  }
327
323
 
328
324
  private normalizeValue(value: f32): f32 {
@@ -334,7 +330,7 @@ export class Slider extends FlexBox implements DragGestureHost {
334
330
  return clamp(this.minValue + snapped, this.minValue, this.maxValue);
335
331
  }
336
332
 
337
- private setValue(value: f32, emit: bool): void {
333
+ private setValue(value: f32, emit: bool, announce: bool = emit): void {
338
334
  const normalized = this.normalizeValue(value);
339
335
  if (normalized == this.currentValue) {
340
336
  this.syncPresentation();
@@ -344,14 +340,17 @@ export class Slider extends FlexBox implements DragGestureHost {
344
340
  this.semanticValueRange(this.currentValue, this.minValue, this.maxValue);
345
341
  this.syncPresentation();
346
342
  if (emit) {
347
- this.requestSemanticAnnouncement();
343
+ if (announce) {
344
+ this.requestSemanticAnnouncement();
345
+ }
346
+ const event = new SliderChangedEventArgs(this.currentValue);
348
347
  const callback = this.changedCallback;
349
348
  if (callback !== null) {
350
- callback(this.currentValue);
349
+ callback(event);
351
350
  }
352
351
  const binding = this.changedBinding;
353
352
  if (binding !== null) {
354
- binding.invoke(this.currentValue);
353
+ binding.invoke(event);
355
354
  }
356
355
  }
357
356
  }
@@ -401,8 +400,7 @@ export class Slider extends FlexBox implements DragGestureHost {
401
400
  this.cornerRadius(theme.spacing.sm);
402
401
  this.border(
403
402
  SLIDER_FOCUS_BORDER_WIDTH,
404
- theme.colors.background,
405
- BorderStyle.Solid,
403
+ theme.colors.background
406
404
  );
407
405
  this.padding(SLIDER_PADDING, SLIDER_PADDING, SLIDER_PADDING, SLIDER_PADDING);
408
406
  this.opacity(this.isEnabled ? 1.0 : 0.6);
@@ -1,8 +1,10 @@
1
1
  import { Callback1, Handler1 } from "../core/BoundCallback";
2
2
  import { SemanticCheckedState, SemanticRole } from "../core/ffi";
3
+ import { SwitchChangedEventArgs } from "../core/Node";
3
4
  import { PersistedBoolCodec, PersistedValueState } from "../core/PersistedState";
4
5
  import { bind1 } from "../core/bind";
5
6
  import { activeTheme } from "../core/Theme";
7
+ import { LabeledControlSizing } from "./ControlSizing";
6
8
  import { getControlTemplates } from "./ControlTemplateSet";
7
9
  import { PressableLabeledControl } from "./internal/PressableLabeledControl";
8
10
  import {
@@ -30,24 +32,25 @@ class PersistedSwitchState extends PersistedValueState<Switch, bool> {
30
32
 
31
33
  const SWITCH_PERSISTED_STATE = new PersistedSwitchState();
32
34
 
33
- function createIndicatorPresenter(template: SwitchIndicatorTemplate | null): SwitchIndicatorPresenter {
35
+ function createIndicatorPresenter(template: SwitchIndicatorTemplate | null, sizing: LabeledControlSizing | null = null): SwitchIndicatorPresenter {
34
36
  if (template !== null) {
35
- return template.create();
37
+ return template.create(sizing);
36
38
  }
37
39
  const templateSet = getControlTemplates();
38
40
  const appTemplate = templateSet !== null ? templateSet.switchIndicator : null;
39
- return (appTemplate === null ? defaultSwitchIndicatorTemplate : appTemplate).create();
41
+ return (appTemplate === null ? defaultSwitchIndicatorTemplate : appTemplate).create(sizing);
40
42
  }
41
43
 
42
44
  export class Switch extends PressableLabeledControl {
43
45
  private indicatorPresenter: SwitchIndicatorPresenter;
44
46
  private templateOverride: SwitchIndicatorTemplate | null = null;
47
+ private sizingValue: LabeledControlSizing | null = null;
45
48
  private checkedValue: bool = false;
46
- private changedCallback: ((checked: bool) => void) | null = null;
47
- private changedBinding: Callback1<bool> | null = null;
49
+ private changedCallback: ((event: SwitchChangedEventArgs) => void) | null = null;
50
+ private changedBinding: Callback1<SwitchChangedEventArgs> | null = null;
48
51
 
49
52
  constructor(label: string) {
50
- const indicatorPresenter = createIndicatorPresenter(null);
53
+ const indicatorPresenter = createIndicatorPresenter(null, null);
51
54
  super(SemanticRole.Switch, label, indicatorPresenter.root);
52
55
  this.indicatorPresenter = indicatorPresenter;
53
56
  this.semanticChecked(SemanticCheckedState.False);
@@ -60,31 +63,42 @@ export class Switch extends PressableLabeledControl {
60
63
  }
61
64
 
62
65
  check(flag: bool): this {
63
- this.updateChecked(flag, false);
66
+ this.updateChecked(flag, true, false);
67
+ return this;
68
+ }
69
+
70
+ sizing(sizing: LabeledControlSizing | null): this {
71
+ this.sizingValue = sizing;
72
+ this.setLabelFontSizeOverride(
73
+ sizing !== null && sizing.hasLabelFontSize ? sizing.labelFontSizePx : 0.0,
74
+ );
75
+ this.indicatorPresenter = createIndicatorPresenter(this.templateOverride, this.sizingValue);
76
+ this.replaceIndicatorRoot(this.indicatorPresenter.root);
77
+ this.syncVisualState();
64
78
  return this;
65
79
  }
66
80
 
67
81
  template(template: SwitchIndicatorTemplate | null): this {
68
82
  this.templateOverride = template;
69
- this.indicatorPresenter = createIndicatorPresenter(this.templateOverride);
83
+ this.indicatorPresenter = createIndicatorPresenter(this.templateOverride, this.sizingValue);
70
84
  this.replaceIndicatorRoot(this.indicatorPresenter.root);
71
85
  this.syncVisualState();
72
86
  return this;
73
87
  }
74
88
 
75
- onChanged(callback: ((checked: bool) => void) | null): this {
89
+ onChanged(callback: ((event: SwitchChangedEventArgs) => void) | null): this {
76
90
  this.changedCallback = callback;
77
91
  this.changedBinding = null;
78
92
  return this;
79
93
  }
80
94
 
81
- bindChanged<Owner>(owner: Owner, handler: Handler1<Owner, bool>): this {
95
+ bindChanged<Owner>(owner: Owner, handler: Handler1<Owner, SwitchChangedEventArgs>): this {
82
96
  this.changedCallback = null;
83
- this.changedBinding = bind1<Owner, bool>(owner, handler);
97
+ this.changedBinding = bind1<Owner, SwitchChangedEventArgs>(owner, handler);
84
98
  return this;
85
99
  }
86
100
 
87
- onChangedWith<Owner>(owner: Owner, handler: Handler1<Owner, bool>): this {
101
+ onChangedWith<Owner>(owner: Owner, handler: Handler1<Owner, SwitchChangedEventArgs>): this {
88
102
  this.bindChanged(owner, handler);
89
103
  return this;
90
104
  }
@@ -108,10 +122,10 @@ export class Switch extends PressableLabeledControl {
108
122
  }
109
123
 
110
124
  _applyPersistedChecked(next: bool): void {
111
- this.updateChecked(next, true);
125
+ this.updateChecked(next, true, false);
112
126
  }
113
127
 
114
- private updateChecked(next: bool, emit: bool): void {
128
+ private updateChecked(next: bool, emit: bool, announce: bool = emit): void {
115
129
  if (this.checkedValue == next) {
116
130
  return;
117
131
  }
@@ -119,14 +133,17 @@ export class Switch extends PressableLabeledControl {
119
133
  this.semanticChecked(next ? SemanticCheckedState.True : SemanticCheckedState.False);
120
134
  this.syncVisualState();
121
135
  if (emit) {
122
- this.requestSemanticAnnouncement();
136
+ if (announce) {
137
+ this.requestSemanticAnnouncement();
138
+ }
139
+ const event = new SwitchChangedEventArgs(next);
123
140
  const callback = this.changedCallback;
124
141
  if (callback !== null) {
125
- callback(next);
142
+ callback(event);
126
143
  }
127
144
  const binding = this.changedBinding;
128
145
  if (binding !== null) {
129
- binding.invoke(next);
146
+ binding.invoke(event);
130
147
  }
131
148
  }
132
149
  }