drawnui-react 0.1.0-preview.15 → 0.1.0-preview.17
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/README.md +1 -1
- package/SKIPPED.md +9 -8
- package/dist/controls/AnimatedFramesRenderer.d.ts +7 -0
- package/dist/controls/AnimatedFramesRenderer.js +16 -1
- package/dist/controls/DrawnGame.d.ts +4 -1
- package/dist/controls/DrawnGame.js +7 -3
- package/dist/controls/GridStructure.d.ts +13 -1
- package/dist/controls/GridStructure.js +38 -2
- package/dist/controls/SkiaBackdrop.d.ts +2 -0
- package/dist/controls/SkiaBackdrop.js +2 -0
- package/dist/controls/SkiaButton.d.ts +2 -0
- package/dist/controls/SkiaButton.js +2 -0
- package/dist/controls/SkiaCarousel.d.ts +3 -1
- package/dist/controls/SkiaCarousel.js +5 -2
- package/dist/controls/SkiaDrawer.d.ts +2 -0
- package/dist/controls/SkiaDrawer.js +2 -0
- package/dist/controls/SkiaEditor.d.ts +5 -1
- package/dist/controls/SkiaEditor.js +29 -18
- package/dist/controls/SkiaGif.d.ts +3 -0
- package/dist/controls/SkiaGif.js +11 -1
- package/dist/controls/SkiaImage.js +15 -10
- package/dist/controls/SkiaLabel.d.ts +54 -3
- package/dist/controls/SkiaLabel.js +235 -52
- package/dist/controls/SkiaLayout.d.ts +20 -0
- package/dist/controls/SkiaLayout.js +78 -6
- package/dist/controls/SkiaLottie.js +3 -1
- package/dist/controls/SkiaProgress.d.ts +2 -1
- package/dist/controls/SkiaProgress.js +6 -3
- package/dist/controls/SkiaScroll.d.ts +16 -0
- package/dist/controls/SkiaScroll.js +85 -8
- package/dist/controls/SkiaShape.d.ts +13 -2
- package/dist/controls/SkiaShape.js +50 -10
- package/dist/controls/SkiaSlider.d.ts +7 -1
- package/dist/controls/SkiaSlider.js +12 -4
- package/dist/controls/SkiaSprite.d.ts +1 -0
- package/dist/controls/SkiaSprite.js +4 -0
- package/dist/controls/SkiaToggle.d.ts +2 -0
- package/dist/controls/SkiaToggle.js +3 -1
- package/dist/controls/SnappingLayout.d.ts +7 -0
- package/dist/controls/SnappingLayout.js +11 -0
- package/dist/core/Accessibility.d.ts +21 -0
- package/dist/core/Accessibility.js +66 -9
- package/dist/core/Animators.d.ts +28 -1
- package/dist/core/Animators.js +76 -8
- package/dist/core/Canvas.d.ts +26 -4
- package/dist/core/Canvas.js +136 -23
- package/dist/core/Easing.d.ts +12 -1
- package/dist/core/Easing.js +25 -1
- package/dist/core/Gestures.d.ts +24 -1
- package/dist/core/Gestures.js +75 -2
- package/dist/core/Hover.d.ts +47 -0
- package/dist/core/Hover.js +134 -0
- package/dist/core/KeyboardManager.d.ts +13 -0
- package/dist/core/KeyboardManager.js +18 -0
- package/dist/core/ScrollAnimators.js +9 -0
- package/dist/core/SkiaControl.d.ts +97 -1
- package/dist/core/SkiaControl.js +271 -38
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/react/SkiaShell.js +33 -14
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.js +30 -3
- package/dist/react/reconciler.js +29 -10
- package/package.json +18 -1
|
@@ -112,7 +112,22 @@ export declare class SkiaLayout extends SkiaControl {
|
|
|
112
112
|
get Views(): readonly SkiaControl[];
|
|
113
113
|
/** Settable children list like DrawnUi Children (ignored while templated). */
|
|
114
114
|
get Children(): readonly SkiaControl[];
|
|
115
|
+
/**
|
|
116
|
+
* C# Children reset (ChildrenCollectionSync, 66a1eb02): the app's children the new list no longer holds are removed,
|
|
117
|
+
* the ones it gained are added, then all of them take the list's order inside the slots app children occupy, so the
|
|
118
|
+
* parts a control made itself keep their place.
|
|
119
|
+
*/
|
|
115
120
|
set Children(value: readonly SkiaControl[]);
|
|
121
|
+
/**
|
|
122
|
+
* C# Insert / Move of a Children collection (the reconciler's appendChild / insertBefore): `child` goes before
|
|
123
|
+
* `before` among the app's children, or last without it. A new child is attached at the end of the views and an
|
|
124
|
+
* append stops there; otherwise the app's children take their new order inside the slots they occupy.
|
|
125
|
+
*/
|
|
126
|
+
InsertChild(child: SkiaControl, before?: SkiaControl): void;
|
|
127
|
+
/** C# OrderViews: the given children, in their order, inside the slots they occupy in the views; nothing else moves. */
|
|
128
|
+
private OrderChildren;
|
|
129
|
+
/** C# ClearChildren: removes every subview, the control's own parts included. */
|
|
130
|
+
ClearChildren(): void;
|
|
116
131
|
private orderedViews?;
|
|
117
132
|
/** Static children sorted by ZIndex (stable), computed once per change (C# GetOrderedSubviews). */
|
|
118
133
|
protected GetOrderedSubviews(): readonly SkiaControl[];
|
|
@@ -150,6 +165,11 @@ export declare class SkiaLayout extends SkiaControl {
|
|
|
150
165
|
private MvScheduleBackground;
|
|
151
166
|
/** Binds a cell to items[index] (through the adapter, so MeasureFirst's cell 0 stays realized) and measures it. */
|
|
152
167
|
private MeasureItem;
|
|
168
|
+
/**
|
|
169
|
+
* The item's offset and height are real, not estimated (C# LastMeasuredIndexLocal >= index): MeasureVisible knows
|
|
170
|
+
* them once the measured prefix passed the item; the other strategies always do.
|
|
171
|
+
*/
|
|
172
|
+
IsItemMeasured(index: number): boolean;
|
|
153
173
|
/** Pixel offset of item index from the top of the layout content (inside padding). */
|
|
154
174
|
GetItemOffsetPixels(index: number): number;
|
|
155
175
|
private ItemHeightPixels;
|
|
@@ -359,11 +359,67 @@ export class SkiaLayout extends SkiaControl {
|
|
|
359
359
|
get Views() { return this.IsTemplated ? this.ChildrenFactory.GetViewsInUse() : this.views; }
|
|
360
360
|
/** Settable children list like DrawnUi Children (ignored while templated). */
|
|
361
361
|
get Children() { return this.views; }
|
|
362
|
+
/**
|
|
363
|
+
* C# Children reset (ChildrenCollectionSync, 66a1eb02): the app's children the new list no longer holds are removed,
|
|
364
|
+
* the ones it gained are added, then all of them take the list's order inside the slots app children occupy, so the
|
|
365
|
+
* parts a control made itself keep their place.
|
|
366
|
+
*/
|
|
362
367
|
set Children(value) {
|
|
368
|
+
const keep = new Set(value);
|
|
369
|
+
for (const v of [...this.views])
|
|
370
|
+
if (v.IsChildrenItem && !keep.has(v))
|
|
371
|
+
this.RemoveSubView(v);
|
|
372
|
+
const inViews = new Set(this.views);
|
|
373
|
+
for (const v of value) {
|
|
374
|
+
v.IsChildrenItem = true;
|
|
375
|
+
if (!inViews.has(v))
|
|
376
|
+
this.AddSubView(v);
|
|
377
|
+
}
|
|
378
|
+
this.OrderChildren(value);
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* C# Insert / Move of a Children collection (the reconciler's appendChild / insertBefore): `child` goes before
|
|
382
|
+
* `before` among the app's children, or last without it. A new child is attached at the end of the views and an
|
|
383
|
+
* append stops there; otherwise the app's children take their new order inside the slots they occupy.
|
|
384
|
+
*/
|
|
385
|
+
InsertChild(child, before) {
|
|
386
|
+
child.IsChildrenItem = true;
|
|
387
|
+
const attached = child.Parent === this && this.views.includes(child);
|
|
388
|
+
if (!attached)
|
|
389
|
+
this.AddSubView(child);
|
|
390
|
+
if (!attached && !before)
|
|
391
|
+
return;
|
|
392
|
+
const order = this.views.filter((v) => v.IsChildrenItem && v !== child);
|
|
393
|
+
const at = before ? order.indexOf(before) : -1;
|
|
394
|
+
order.splice(at < 0 ? order.length : at, 0, child);
|
|
395
|
+
this.OrderChildren(order);
|
|
396
|
+
}
|
|
397
|
+
/** C# OrderViews: the given children, in their order, inside the slots they occupy in the views; nothing else moves. */
|
|
398
|
+
OrderChildren(ordered) {
|
|
399
|
+
const inViews = new Set(this.views);
|
|
400
|
+
const present = ordered.filter((v) => inViews.delete(v));
|
|
401
|
+
if (present.length < 2)
|
|
402
|
+
return;
|
|
403
|
+
const isChild = new Set(present);
|
|
404
|
+
let next = 0, changed = false;
|
|
405
|
+
for (let i = 0; i < this.views.length && next < present.length; i++) {
|
|
406
|
+
if (!isChild.has(this.views[i]))
|
|
407
|
+
continue;
|
|
408
|
+
if (this.views[i] !== present[next]) {
|
|
409
|
+
this.views[i] = present[next];
|
|
410
|
+
changed = true;
|
|
411
|
+
}
|
|
412
|
+
next++;
|
|
413
|
+
}
|
|
414
|
+
if (changed) {
|
|
415
|
+
this.orderedViews = undefined;
|
|
416
|
+
this.InvalidateMeasure();
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
/** C# ClearChildren: removes every subview, the control's own parts included. */
|
|
420
|
+
ClearChildren() {
|
|
363
421
|
for (const v of [...this.views])
|
|
364
422
|
this.RemoveSubView(v);
|
|
365
|
-
for (const v of value)
|
|
366
|
-
this.AddSubView(v);
|
|
367
423
|
}
|
|
368
424
|
orderedViews;
|
|
369
425
|
/** Static children sorted by ZIndex (stable), computed once per change (C# GetOrderedSubviews). */
|
|
@@ -390,10 +446,18 @@ export class SkiaLayout extends SkiaControl {
|
|
|
390
446
|
}
|
|
391
447
|
AddSubView(control) { this.InsertSubView(this.views.length, control); }
|
|
392
448
|
InsertSubView(index, control) {
|
|
449
|
+
// already a child: a move (React reorders keyed children by inserting an existing one elsewhere), never a 2nd copy
|
|
450
|
+
const at = control.Parent === this ? this.views.indexOf(control) : -1;
|
|
451
|
+
if (at >= 0) {
|
|
452
|
+
this.views.splice(at, 1);
|
|
453
|
+
if (at < index)
|
|
454
|
+
index--;
|
|
455
|
+
}
|
|
393
456
|
control.Parent = this;
|
|
394
|
-
this.views.splice(index, 0, control);
|
|
457
|
+
this.views.splice(Math.min(Math.max(0, index), this.views.length), 0, control);
|
|
395
458
|
this.orderedViews = undefined;
|
|
396
459
|
this.InvalidateMeasure();
|
|
460
|
+
this.Superview?.Hover?.RequestCheck(); // a popup / page under a still mouse
|
|
397
461
|
}
|
|
398
462
|
RemoveSubView(control) {
|
|
399
463
|
const i = this.views.indexOf(control);
|
|
@@ -403,6 +467,7 @@ export class SkiaLayout extends SkiaControl {
|
|
|
403
467
|
this.orderedViews = undefined;
|
|
404
468
|
control.Parent = undefined;
|
|
405
469
|
this.InvalidateMeasure();
|
|
470
|
+
this.Superview?.Hover?.RequestCheck();
|
|
406
471
|
}
|
|
407
472
|
// ---- measure ----
|
|
408
473
|
MeasureAbsolute(widthConstraint, heightConstraint, scale) {
|
|
@@ -666,6 +731,11 @@ export class SkiaLayout extends SkiaControl {
|
|
|
666
731
|
this.ChildrenFactory.ReleaseViewAt(index);
|
|
667
732
|
return h;
|
|
668
733
|
}
|
|
734
|
+
/**
|
|
735
|
+
* The item's offset and height are real, not estimated (C# LastMeasuredIndexLocal >= index): MeasureVisible knows
|
|
736
|
+
* them once the measured prefix passed the item; the other strategies always do.
|
|
737
|
+
*/
|
|
738
|
+
IsItemMeasured(index) { return this.MeasureItemsStrategy !== "MeasureVisible" || index < this.mvMeasured; }
|
|
669
739
|
/** Pixel offset of item index from the top of the layout content (inside padding). */
|
|
670
740
|
GetItemOffsetPixels(index) {
|
|
671
741
|
const scale = this.RenderingScale;
|
|
@@ -758,9 +828,11 @@ export class SkiaLayout extends SkiaControl {
|
|
|
758
828
|
return;
|
|
759
829
|
}
|
|
760
830
|
const composing = this.IsRenderingWithComposition;
|
|
761
|
-
for (const v of this.GetOrderedSubviews())
|
|
762
|
-
if (
|
|
763
|
-
|
|
831
|
+
for (const v of this.GetOrderedSubviews()) {
|
|
832
|
+
if (composing && !this.DirtyChildrenInternal.has(v))
|
|
833
|
+
continue;
|
|
834
|
+
v.Render(ctx); // a child entirely outside the clip skips itself
|
|
835
|
+
}
|
|
764
836
|
}
|
|
765
837
|
GetCompositeChildren() { return this.IsTemplatedList || this.IsRecycledLayout ? [] : this.GetOrderedSubviews(); }
|
|
766
838
|
drawnSlots = new Set();
|
|
@@ -32,7 +32,9 @@ export class SkiaLottie extends AnimatedFramesRenderer {
|
|
|
32
32
|
Animation;
|
|
33
33
|
constructor() {
|
|
34
34
|
super();
|
|
35
|
-
|
|
35
|
+
// C# ImageDoubleBuffered pays off where a thread bakes the bitmap; on the web it is one offscreen pass per frame
|
|
36
|
+
// while playing, so the web engines default to Operations (drawnui-cross rule 3)
|
|
37
|
+
this.UseCache = "Operations";
|
|
36
38
|
}
|
|
37
39
|
get Source() { return this.source; }
|
|
38
40
|
set Source(v) { if (this.source !== v) {
|
|
@@ -36,5 +36,6 @@ export declare class SkiaProgress extends SkiaControl {
|
|
|
36
36
|
get Ratio(): number;
|
|
37
37
|
protected MeasureAbsolute(w: number, _h: number, scale: number): ScaledSize;
|
|
38
38
|
protected Paint(ctx: DrawingContext): void;
|
|
39
|
-
|
|
39
|
+
/** Value between Min and Max, read as "65%"; the name is the app's AccessibilityLabel only (drawnui-cross 6c). */
|
|
40
|
+
get AccessibilityValue(): import("../core/Accessibility").AccessibilityValue;
|
|
40
41
|
}
|
|
@@ -33,9 +33,9 @@ export class SkiaProgress extends SkiaControl {
|
|
|
33
33
|
set Max(v) { this.max = v; this.Update(); }
|
|
34
34
|
/** Unset = per-style palette. */
|
|
35
35
|
get TrackColor() { return this.trackColor ?? SkiaProgress.Palette(this.UsingControlStyle).track; }
|
|
36
|
-
set TrackColor(v) { this.trackColor = v; this.
|
|
36
|
+
set TrackColor(v) { this.trackColor = v; this.UpdateDraw(); }
|
|
37
37
|
get ProgressColor() { return this.progressColor ?? SkiaProgress.Palette(this.UsingControlStyle).progress; }
|
|
38
|
-
set ProgressColor(v) { this.progressColor = v; this.
|
|
38
|
+
set ProgressColor(v) { this.progressColor = v; this.UpdateDraw(); }
|
|
39
39
|
/** C# ResolvedTrackColor / ResolvedProgressColor / track heights per style. */
|
|
40
40
|
static Palette(s) {
|
|
41
41
|
switch (s) {
|
|
@@ -76,5 +76,8 @@ export class SkiaProgress extends SkiaControl {
|
|
|
76
76
|
}
|
|
77
77
|
paint.delete();
|
|
78
78
|
}
|
|
79
|
-
|
|
79
|
+
/** Value between Min and Max, read as "65%"; the name is the app's AccessibilityLabel only (drawnui-cross 6c). */
|
|
80
|
+
get AccessibilityValue() {
|
|
81
|
+
return { Now: this.value, Min: this.min, Max: this.max, Step: 0, Text: `${Math.round(this.Ratio * 100)}%` };
|
|
82
|
+
}
|
|
80
83
|
}
|
|
@@ -156,6 +156,10 @@ export declare class SkiaScroll extends SkiaControl {
|
|
|
156
156
|
set ViewportOffsetX(value: number);
|
|
157
157
|
get ViewportOffsetY(): number;
|
|
158
158
|
set ViewportOffsetY(value: number);
|
|
159
|
+
/** An offset set without a glide or a pan (a jump, a touchpad step): the controls under a still mouse changed. */
|
|
160
|
+
private OffsetJumped;
|
|
161
|
+
/** Hover waits while the content glides, flings, bounces or follows a pan (C# IsScrolling). */
|
|
162
|
+
MovesContent(): boolean;
|
|
159
163
|
private readonly animatorFlingX;
|
|
160
164
|
private readonly animatorFlingY;
|
|
161
165
|
private readonly bounceX;
|
|
@@ -214,6 +218,18 @@ export declare class SkiaScroll extends SkiaControl {
|
|
|
214
218
|
* templated layout (the recycled list is the scroll's only child; a header goes above the scroll or in Header).
|
|
215
219
|
*/
|
|
216
220
|
ScrollToIndex(index: number, animate: boolean, option?: RelativePositionType): void;
|
|
221
|
+
/**
|
|
222
|
+
* An open ScrollToIndex (C# OrderedScrollToIndex, DrawnUi.Rust scroll_to_index): a row not measured yet is gone to by
|
|
223
|
+
* the sizes as they are estimated, and the order is aimed again every frame until the row has its real place and the
|
|
224
|
+
* viewport stands on it; an animated move goes on to a moved target in the time it has left, later corrections jump.
|
|
225
|
+
* A press, the wheel or another scroll drops it; while it is open LoadMore waits.
|
|
226
|
+
*/
|
|
227
|
+
private indexOrder?;
|
|
228
|
+
private pursuing;
|
|
229
|
+
/** One step of the open order (C# ExecuteScrollToIndexOrder, Rust `pursue`), at the start of every paint. */
|
|
230
|
+
private PursueIndexOrder;
|
|
231
|
+
/** The offset (points) that puts item `index` where `option` says, by the sizes the list knows now; Exact = its place is measured. */
|
|
232
|
+
private AimIndex;
|
|
217
233
|
private StopAnimators;
|
|
218
234
|
/** DrawnUi DecelerationRatio: FrictionScrolled / 100, floored at 0.1 friction. */
|
|
219
235
|
private get DecelerationRatio();
|
|
@@ -333,6 +333,8 @@ export class SkiaScroll extends SkiaControl {
|
|
|
333
333
|
loadMoreTopArmed = false;
|
|
334
334
|
/** C# CheckNeedToLoadMore: fires once per content extent near an edge; re-arms when the content grows or the user moves away (>offset+100pt, >2 s). */
|
|
335
335
|
CheckLoadMore() {
|
|
336
|
+
if (this.indexOrder)
|
|
337
|
+
return; // an open ScrollToIndex has the viewport on its way: the edges are looked at after it
|
|
336
338
|
const vertical = this.Orientation !== "Horizontal";
|
|
337
339
|
const offset = vertical ? this.offsetY : this.offsetX;
|
|
338
340
|
const min = vertical ? this.ContentOffsetBounds.Top : this.ContentOffsetBounds.Left; // most negative offset
|
|
@@ -399,12 +401,19 @@ export class SkiaScroll extends SkiaControl {
|
|
|
399
401
|
set ViewportOffsetX(value) { if (this.offsetX !== value) {
|
|
400
402
|
this.offsetX = value;
|
|
401
403
|
this.OnScrolled();
|
|
404
|
+
this.OffsetJumped();
|
|
402
405
|
} }
|
|
403
406
|
get ViewportOffsetY() { return this.offsetY; }
|
|
404
407
|
set ViewportOffsetY(value) { if (this.offsetY !== value) {
|
|
405
408
|
this.offsetY = value;
|
|
406
409
|
this.OnScrolled();
|
|
410
|
+
this.OffsetJumped();
|
|
407
411
|
} }
|
|
412
|
+
/** An offset set without a glide or a pan (a jump, a touchpad step): the controls under a still mouse changed. */
|
|
413
|
+
OffsetJumped() { if (!this.MovesContent())
|
|
414
|
+
this.Superview?.Hover?.RequestCheck(); }
|
|
415
|
+
/** Hover waits while the content glides, flings, bounces or follows a pan (C# IsScrolling). */
|
|
416
|
+
MovesContent() { return this.IsScrolling || this.IsUserPanning || !!this.draggedScrollBar; }
|
|
408
417
|
animatorFlingX = new ScrollFlingAnimator(this);
|
|
409
418
|
animatorFlingY = new ScrollFlingAnimator(this);
|
|
410
419
|
bounceX = new SpringWithVelocityAnimator(this);
|
|
@@ -506,6 +515,7 @@ export class SkiaScroll extends SkiaControl {
|
|
|
506
515
|
}
|
|
507
516
|
InsertSubView(_index, control) { this.AddSubView(control); }
|
|
508
517
|
RemoveSubView(control) {
|
|
518
|
+
this.Superview?.Hover?.RequestCheck();
|
|
509
519
|
if (this.content === control)
|
|
510
520
|
this.Content = undefined;
|
|
511
521
|
else if (this.header === control)
|
|
@@ -626,6 +636,8 @@ export class SkiaScroll extends SkiaControl {
|
|
|
626
636
|
}
|
|
627
637
|
}
|
|
628
638
|
Paint(ctx) {
|
|
639
|
+
this.Superview?.Hover?.RegisterMover(this);
|
|
640
|
+
this.PursueIndexOrder();
|
|
629
641
|
const c = this.content;
|
|
630
642
|
if (!c)
|
|
631
643
|
return;
|
|
@@ -728,6 +740,8 @@ export class SkiaScroll extends SkiaControl {
|
|
|
728
740
|
this.ViewportOffsetY = target;
|
|
729
741
|
}
|
|
730
742
|
ScrollTo(x, y, maxSpeedSecs, clamp = true) {
|
|
743
|
+
if (!this.pursuing)
|
|
744
|
+
this.indexOrder = undefined; // another scroll drops an open ScrollToIndex
|
|
731
745
|
this.StopAnimators(); // also forgets any pending edge bounce: a programmatic scroll never bounces
|
|
732
746
|
let tx = x, ty = y;
|
|
733
747
|
if (clamp) {
|
|
@@ -760,16 +774,82 @@ export class SkiaScroll extends SkiaControl {
|
|
|
760
774
|
else
|
|
761
775
|
this.ScrollTo(this.offsetX, this.ContentOffsetBounds.Top, maxTimeSecs);
|
|
762
776
|
}
|
|
763
|
-
StopScrolling() { this.StopAnimators(); this.IsUserPanning = false; }
|
|
777
|
+
StopScrolling() { this.indexOrder = undefined; this.StopAnimators(); this.IsUserPanning = false; }
|
|
764
778
|
/**
|
|
765
779
|
* Scrolls so that item `index` is at the viewport start (or end). Like DrawnUi, Content must BE the
|
|
766
780
|
* templated layout (the recycled list is the scroll's only child; a header goes above the scroll or in Header).
|
|
767
781
|
*/
|
|
768
782
|
ScrollToIndex(index, animate, option = "Start") {
|
|
783
|
+
this.indexOrder = { Index: index, Option: option, Secs: animate ? this.ScrollingSpeedMs / 1000 : 0, Stalled: 0 };
|
|
784
|
+
this.PursueIndexOrder();
|
|
785
|
+
this.Repaint();
|
|
786
|
+
}
|
|
787
|
+
/**
|
|
788
|
+
* An open ScrollToIndex (C# OrderedScrollToIndex, DrawnUi.Rust scroll_to_index): a row not measured yet is gone to by
|
|
789
|
+
* the sizes as they are estimated, and the order is aimed again every frame until the row has its real place and the
|
|
790
|
+
* viewport stands on it; an animated move goes on to a moved target in the time it has left, later corrections jump.
|
|
791
|
+
* A press, the wheel or another scroll drops it; while it is open LoadMore waits.
|
|
792
|
+
*/
|
|
793
|
+
indexOrder;
|
|
794
|
+
pursuing = false;
|
|
795
|
+
/** One step of the open order (C# ExecuteScrollToIndexOrder, Rust `pursue`), at the start of every paint. */
|
|
796
|
+
PursueIndexOrder() {
|
|
797
|
+
const order = this.indexOrder;
|
|
798
|
+
if (!order)
|
|
799
|
+
return;
|
|
800
|
+
const horizontal = this.Orientation === "Horizontal";
|
|
801
|
+
const before = horizontal ? this.offsetX : this.offsetY;
|
|
802
|
+
const running = horizontal ? this.animatorFlingX : this.animatorFlingY;
|
|
803
|
+
const aim = this.AimIndex(order.Index, order.Option);
|
|
804
|
+
let done = false;
|
|
805
|
+
if (aim) {
|
|
806
|
+
const c = this.ClampOffset(horizontal ? aim.Offset : this.offsetX, horizontal ? this.offsetY : aim.Offset, this.ContentOffsetBounds, true);
|
|
807
|
+
const target = horizontal ? c.X : c.Y;
|
|
808
|
+
const runningTo = horizontal ? this.scrollToTargetX : this.scrollToTargetY;
|
|
809
|
+
const move = (to, secs) => {
|
|
810
|
+
this.pursuing = true;
|
|
811
|
+
try {
|
|
812
|
+
this.ScrollTo(horizontal ? to : this.offsetX, horizontal ? this.offsetY : to, secs, true);
|
|
813
|
+
}
|
|
814
|
+
finally {
|
|
815
|
+
this.pursuing = false;
|
|
816
|
+
}
|
|
817
|
+
};
|
|
818
|
+
if (running.IsRunning && runningTo !== null) {
|
|
819
|
+
if (Math.abs(runningTo - target) > 0.5) {
|
|
820
|
+
// on the way: the move goes on to the new target in the time it has left
|
|
821
|
+
const now = this.Superview?.FrameTimeNanos || performance.now() * 1_000_000;
|
|
822
|
+
move(target, running.StartFrameTimeNanos ? Math.max(0.016, running.Speed - (now - running.StartFrameTimeNanos) / 1e9) : running.Speed);
|
|
823
|
+
running.StartFrameTimeNanos = running.LastFrameTimeNanos = now;
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
else if (Math.abs(before - target) <= 0.5) {
|
|
827
|
+
if (horizontal)
|
|
828
|
+
this.ViewportOffsetX = target;
|
|
829
|
+
else
|
|
830
|
+
this.ViewportOffsetY = target;
|
|
831
|
+
done = aim.Exact;
|
|
832
|
+
}
|
|
833
|
+
else {
|
|
834
|
+
move(target, order.Secs);
|
|
835
|
+
order.Secs = 0;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
// no list yet, or a row that never gets its real place: not forever
|
|
839
|
+
order.Stalled = (horizontal ? this.offsetX : this.offsetY) === before && !running.IsRunning ? order.Stalled + 1 : 0;
|
|
840
|
+
if (done || order.Stalled >= 10) {
|
|
841
|
+
this.indexOrder = undefined;
|
|
842
|
+
this.CheckLoadMore();
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
this.Repaint(); // the next frame aims again
|
|
846
|
+
}
|
|
847
|
+
/** The offset (points) that puts item `index` where `option` says, by the sizes the list knows now; Exact = its place is measured. */
|
|
848
|
+
AimIndex(index, option) {
|
|
769
849
|
const layout = this.content instanceof SkiaLayout && this.content.IsTemplated ? this.content : undefined;
|
|
770
850
|
const items = layout?.ItemsSource;
|
|
771
851
|
if (!layout || !items || items.length === 0 || !this.content)
|
|
772
|
-
return;
|
|
852
|
+
return undefined;
|
|
773
853
|
const i = Math.max(0, Math.min(items.length - 1, index));
|
|
774
854
|
const scale = this.RenderingScale;
|
|
775
855
|
const horizontal = this.Orientation === "Horizontal";
|
|
@@ -786,7 +866,7 @@ export class SkiaScroll extends SkiaControl {
|
|
|
786
866
|
// arranged rect, like C# reads the structure cell's Destination.
|
|
787
867
|
const cell = layout.ChildrenFactory.GetViewForIndex(i);
|
|
788
868
|
if (!cell)
|
|
789
|
-
return;
|
|
869
|
+
return undefined;
|
|
790
870
|
const r = cell.DrawingRect, c = this.content.DrawingRect;
|
|
791
871
|
itemStart = (horizontal ? r.Left - c.Left : r.Top - c.Top) / scale;
|
|
792
872
|
itemSize = (horizontal ? r.Width : r.Height) / scale;
|
|
@@ -796,11 +876,7 @@ export class SkiaScroll extends SkiaControl {
|
|
|
796
876
|
target -= viewport - itemSize;
|
|
797
877
|
else if (option === "Center")
|
|
798
878
|
target -= (viewport - itemSize) / 2;
|
|
799
|
-
|
|
800
|
-
if (horizontal)
|
|
801
|
-
this.ScrollTo(-target, this.offsetY, time, true);
|
|
802
|
-
else
|
|
803
|
-
this.ScrollTo(this.offsetX, -target, time, true);
|
|
879
|
+
return { Offset: -target, Exact: layout.IsItemMeasured(i) };
|
|
804
880
|
}
|
|
805
881
|
StopAnimators() {
|
|
806
882
|
this.flingEdgeX = null;
|
|
@@ -886,6 +962,7 @@ export class SkiaScroll extends SkiaControl {
|
|
|
886
962
|
if (this.ProcessScrollBarGestures(args, apply))
|
|
887
963
|
return this;
|
|
888
964
|
if (args.Type === "Down") {
|
|
965
|
+
this.indexOrder = undefined; // a press drops an open ScrollToIndex
|
|
889
966
|
this.hadDown = true;
|
|
890
967
|
this.snapped = false;
|
|
891
968
|
if (this.RespondsToGestures) {
|
|
@@ -20,6 +20,10 @@ export declare class SkiaShape extends SkiaLayout {
|
|
|
20
20
|
StrokeCap: StrokeCap;
|
|
21
21
|
/** Gradient painted along the stroke instead of StrokeColor (C# StrokeGradient). */
|
|
22
22
|
StrokeGradient?: SkiaGradient;
|
|
23
|
+
/** Dashes in points: on, off, on, off... (C# StrokePath, each rounded to pixels). Empty = a solid line. */
|
|
24
|
+
StrokePath?: number[];
|
|
25
|
+
/** Blend mode of the stroke, an SKBlendMode name (C# StrokeBlendMode). */
|
|
26
|
+
StrokeBlendMode: string;
|
|
23
27
|
/** Raised (Bevel) or pressed-in (Emboss) edges, drawn with Bevel after the background (C# BevelType). */
|
|
24
28
|
BevelType: BevelType;
|
|
25
29
|
private bevel?;
|
|
@@ -43,11 +47,18 @@ export declare class SkiaShape extends SkiaLayout {
|
|
|
43
47
|
static ShadowFilter(shadow: SkiaShadow, scale: number): import("canvaskit-wasm").ImageFilter;
|
|
44
48
|
constructor();
|
|
45
49
|
private StrokePixels;
|
|
46
|
-
/**
|
|
50
|
+
/**
|
|
51
|
+
* The outline the stroke runs on (C# CalculateShapeSizeForStroke): the bounds inset by half the stroke rounded up, at
|
|
52
|
+
* least a pixel, then on whole pixels inward, so a 1 px stroke on a plain rectangle sits on the line between two
|
|
53
|
+
* pixels as upstream draws it.
|
|
54
|
+
*/
|
|
47
55
|
private StrokeAwareRect;
|
|
56
|
+
/** The fill (C# MeasuredStrokeAwareClipSize): a third of the stroke inside the outline, so it does not show under the stroke's edge. */
|
|
57
|
+
private BackgroundRect;
|
|
48
58
|
private UsesStroke;
|
|
49
59
|
/** Builds the outline path for rect (canvas pixels). Caller deletes it. */
|
|
50
|
-
|
|
60
|
+
/** `radiusReduce`: pixels taken off every corner radius (the fill inside a thick stroke, C# GetCorrectedBackgroundRadii). */
|
|
61
|
+
protected CreateShapePath(rect: SKRect, scale: number, radiusReduce?: number): Path;
|
|
51
62
|
/** Children live inside the stroke (full width) + Padding. */
|
|
52
63
|
private ChildrenRect;
|
|
53
64
|
/** Clip for overlay effects (ripple) and children: the shape itself, inset by the stroke. */
|
|
@@ -17,6 +17,10 @@ export class SkiaShape extends SkiaLayout {
|
|
|
17
17
|
StrokeCap = "Round";
|
|
18
18
|
/** Gradient painted along the stroke instead of StrokeColor (C# StrokeGradient). */
|
|
19
19
|
StrokeGradient;
|
|
20
|
+
/** Dashes in points: on, off, on, off... (C# StrokePath, each rounded to pixels). Empty = a solid line. */
|
|
21
|
+
StrokePath;
|
|
22
|
+
/** Blend mode of the stroke, an SKBlendMode name (C# StrokeBlendMode). */
|
|
23
|
+
StrokeBlendMode = "SrcOver";
|
|
20
24
|
/** Raised (Bevel) or pressed-in (Emboss) edges, drawn with Bevel after the background (C# BevelType). */
|
|
21
25
|
BevelType = "None";
|
|
22
26
|
bevel;
|
|
@@ -66,14 +70,28 @@ export class SkiaShape extends SkiaLayout {
|
|
|
66
70
|
return 0;
|
|
67
71
|
return this.StrokeWidth > 0 ? this.StrokeWidth * scale : -this.StrokeWidth;
|
|
68
72
|
}
|
|
69
|
-
/**
|
|
73
|
+
/**
|
|
74
|
+
* The outline the stroke runs on (C# CalculateShapeSizeForStroke): the bounds inset by half the stroke rounded up, at
|
|
75
|
+
* least a pixel, then on whole pixels inward, so a 1 px stroke on a plain rectangle sits on the line between two
|
|
76
|
+
* pixels as upstream draws it.
|
|
77
|
+
*/
|
|
70
78
|
StrokeAwareRect(r, scale) {
|
|
71
|
-
|
|
72
|
-
|
|
79
|
+
if (!this.UsesStroke())
|
|
80
|
+
return r;
|
|
81
|
+
const half = this.StrokePixels(scale) / 2, inset = half < 0.5 ? 1 : Math.ceil(half);
|
|
82
|
+
return new SKRect(Math.ceil(r.Left + inset), Math.ceil(r.Top + inset), Math.floor(r.Right - inset), Math.floor(r.Bottom - inset));
|
|
83
|
+
}
|
|
84
|
+
/** The fill (C# MeasuredStrokeAwareClipSize): a third of the stroke inside the outline, so it does not show under the stroke's edge. */
|
|
85
|
+
BackgroundRect(r, scale) {
|
|
86
|
+
if (!this.UsesStroke())
|
|
87
|
+
return r;
|
|
88
|
+
const o = this.StrokeAwareRect(r, scale), k = this.StrokePixels(scale) / 3;
|
|
89
|
+
return new SKRect(o.Left + k, o.Top + k, o.Right - k, o.Bottom - k);
|
|
73
90
|
}
|
|
74
91
|
UsesStroke() { return this.StrokeWidth !== 0 && this.StrokeColor !== Colors.Transparent; }
|
|
75
92
|
/** Builds the outline path for rect (canvas pixels). Caller deletes it. */
|
|
76
|
-
|
|
93
|
+
/** `radiusReduce`: pixels taken off every corner radius (the fill inside a thick stroke, C# GetCorrectedBackgroundRadii). */
|
|
94
|
+
CreateShapePath(rect, scale, radiusReduce = 0) {
|
|
77
95
|
const CK = Super.CK;
|
|
78
96
|
const b = new CK.PathBuilder();
|
|
79
97
|
const type = this.Type;
|
|
@@ -114,7 +132,8 @@ export class SkiaShape extends SkiaLayout {
|
|
|
114
132
|
else {
|
|
115
133
|
const c = this.cornerRadius;
|
|
116
134
|
if (c.TopLeft || c.TopRight || c.BottomLeft || c.BottomRight) {
|
|
117
|
-
const
|
|
135
|
+
const k = (v) => Math.max(0, v * scale - radiusReduce);
|
|
136
|
+
const tl = k(c.TopLeft), tr = k(c.TopRight), br = k(c.BottomRight), bl = k(c.BottomLeft);
|
|
118
137
|
b.addRRect(Float32Array.of(rect.Left, rect.Top, rect.Right, rect.Bottom, tl, tl, tr, tr, br, br, bl, bl));
|
|
119
138
|
}
|
|
120
139
|
else {
|
|
@@ -151,8 +170,11 @@ export class SkiaShape extends SkiaLayout {
|
|
|
151
170
|
return; // open shapes: stroke only
|
|
152
171
|
const CK = Super.CK;
|
|
153
172
|
const canvas = ctx.Context.Canvas;
|
|
154
|
-
const rect = this.
|
|
155
|
-
|
|
173
|
+
const rect = this.BackgroundRect(ctx.Destination, ctx.Scale);
|
|
174
|
+
// inside a stroke wider than a point the corners of the fill are rounded less (C# GetCorrectedBackgroundRadii)
|
|
175
|
+
const outline = this.StrokeAwareRect(ctx.Destination, ctx.Scale);
|
|
176
|
+
const reduce = this.UsesStroke() && this.StrokeWidth > 1 ? Math.min((outline.Width - rect.Width) / 2, (outline.Height - rect.Height) / 2) : 0;
|
|
177
|
+
const path = this.CreateShapePath(rect, ctx.Scale, reduce);
|
|
156
178
|
// C# PaintWithShadowsInternal: the fill is drawn once per shadow with a drop-shadow filter; a hollow shape
|
|
157
179
|
// (ClipBackgroundColor) clips its own outline away so only the shadow outside remains
|
|
158
180
|
for (const shadow of this.shadows) {
|
|
@@ -295,18 +317,36 @@ export class SkiaShape extends SkiaLayout {
|
|
|
295
317
|
clip.delete();
|
|
296
318
|
}
|
|
297
319
|
if (this.UsesStroke()) {
|
|
298
|
-
const
|
|
299
|
-
|
|
320
|
+
const scale = ctx.Scale, px = this.StrokePixels(scale), type = this.Type;
|
|
321
|
+
let rect = this.StrokeAwareRect(ctx.Destination, scale);
|
|
322
|
+
const c = this.cornerRadius;
|
|
323
|
+
const rounded = type === "Rectangle" && !!(c.TopLeft || c.TopRight || c.BottomLeft || c.BottomRight);
|
|
324
|
+
// C# PaintStroke: on curves a stroke of a point or less is thinned (its antialiasing makes it look heavier than
|
|
325
|
+
// the straight parts), a thin rounded rectangle runs through pixel centers, a line is at least a pixel wide
|
|
326
|
+
const curved = rounded || type === "Circle" || type === "Ellipse" || type === "Arc" || type === "Path";
|
|
327
|
+
const width = type === "Line" ? Math.max(1, px) : curved && px <= scale ? px * 0.55 : px;
|
|
328
|
+
if (rounded && px <= 2 * scale) {
|
|
329
|
+
const even = (v) => { const r = Math.round(v); return Math.abs(v % 1) === 0.5 && r % 2 !== 0 ? r - 1 : r; }; // C# Math.Round: ties to even
|
|
330
|
+
rect = new SKRect(even(rect.Left) + 0.5, even(rect.Top) + 0.5, even(rect.Right) - 0.5, even(rect.Bottom) - 0.5);
|
|
331
|
+
}
|
|
332
|
+
const path = this.CreateShapePath(rect, scale);
|
|
300
333
|
const paint = new CK.Paint();
|
|
301
334
|
paint.setAntiAlias(true);
|
|
302
335
|
paint.setStyle(CK.PaintStyle.Stroke);
|
|
303
|
-
paint.setStrokeWidth(
|
|
336
|
+
paint.setStrokeWidth(width);
|
|
304
337
|
paint.setColor(Super.ParseColor(this.StrokeColor));
|
|
305
338
|
if (this.StrokeGradient)
|
|
306
339
|
this.SetupGradient(paint, this.StrokeGradient, rect);
|
|
340
|
+
const blend = CK.BlendMode[this.StrokeBlendMode];
|
|
341
|
+
if (blend && this.StrokeBlendMode !== "SrcOver")
|
|
342
|
+
paint.setBlendMode(blend);
|
|
307
343
|
paint.setStrokeCap(this.StrokeCap === "Butt" ? CK.StrokeCap.Butt : this.StrokeCap === "Square" ? CK.StrokeCap.Square : CK.StrokeCap.Round);
|
|
308
344
|
paint.setStrokeJoin(this.StrokeCap === "Round" ? CK.StrokeJoin.Round : CK.StrokeJoin.Miter);
|
|
345
|
+
const dash = this.StrokePath?.length ? CK.PathEffect.MakeDash(this.StrokePath.map((v) => Math.round(v * scale)), 0) : null;
|
|
346
|
+
if (dash)
|
|
347
|
+
paint.setPathEffect(dash);
|
|
309
348
|
canvas.drawPath(path, paint);
|
|
349
|
+
dash?.delete();
|
|
310
350
|
paint.delete();
|
|
311
351
|
path.delete();
|
|
312
352
|
}
|
|
@@ -8,6 +8,8 @@ import { type Color, ScaledSize, Thickness } from "../core/Types";
|
|
|
8
8
|
* Track, selected trail and thumbs are painted directly; the C# thumb-position math (SliderHeight = thumb box) is kept.
|
|
9
9
|
*/
|
|
10
10
|
export declare class SkiaSlider extends SkiaControl {
|
|
11
|
+
/** Takes mouse hover unless ReceivesHover is set false (C# ReceivesHoverByDefault). */
|
|
12
|
+
protected ReceivesHoverByDefault(): boolean;
|
|
11
13
|
static DefaultAccessibilityRole?: string;
|
|
12
14
|
ControlStyle: PrebuiltControlStyle;
|
|
13
15
|
Min: number;
|
|
@@ -78,5 +80,9 @@ export declare class SkiaSlider extends SkiaControl {
|
|
|
78
80
|
* Home / End go to Min / Max. A ranged slider moves its End thumb, which stops at Start.
|
|
79
81
|
*/
|
|
80
82
|
OnAccessibilityKey(key: string): boolean;
|
|
81
|
-
|
|
83
|
+
/**
|
|
84
|
+
* End between Min and Max, read as the number, or "20 – 80" in range mode; the step is the arrow key's. The name is
|
|
85
|
+
* the app's AccessibilityLabel only (C# used to make the value the name, drawnui-cross 6c).
|
|
86
|
+
*/
|
|
87
|
+
get AccessibilityValue(): import("../core/Accessibility").AccessibilityValue;
|
|
82
88
|
}
|
|
@@ -9,6 +9,8 @@ import { SkiaShape } from "./SkiaShape";
|
|
|
9
9
|
* Track, selected trail and thumbs are painted directly; the C# thumb-position math (SliderHeight = thumb box) is kept.
|
|
10
10
|
*/
|
|
11
11
|
export class SkiaSlider extends SkiaControl {
|
|
12
|
+
/** Takes mouse hover unless ReceivesHover is set false (C# ReceivesHoverByDefault). */
|
|
13
|
+
ReceivesHoverByDefault() { return true; }
|
|
12
14
|
static DefaultAccessibilityRole = "slider";
|
|
13
15
|
ControlStyle = "Unset";
|
|
14
16
|
Min = 0;
|
|
@@ -60,11 +62,11 @@ export class SkiaSlider extends SkiaControl {
|
|
|
60
62
|
get SliderHeight() { return this.sliderHeight ?? this.Look().thumb + (this.EnableRange && this.UsingControlStyle !== "Unset" ? 8 : 0); }
|
|
61
63
|
set SliderHeight(v) { this.sliderHeight = v; this.Update(); }
|
|
62
64
|
get ThumbColor() { return this.thumbColor ?? this.Look().thumbColor; }
|
|
63
|
-
set ThumbColor(v) { this.thumbColor = v; this.
|
|
65
|
+
set ThumbColor(v) { this.thumbColor = v; this.UpdateDraw(); }
|
|
64
66
|
get TrackColor() { return this.trackColor ?? this.Look().track; }
|
|
65
|
-
set TrackColor(v) { this.trackColor = v; this.
|
|
67
|
+
set TrackColor(v) { this.trackColor = v; this.UpdateDraw(); }
|
|
66
68
|
get TrackSelectedColor() { return this.trackSelectedColor ?? this.Look().selected; }
|
|
67
|
-
set TrackSelectedColor(v) { this.trackSelectedColor = v; this.
|
|
69
|
+
set TrackSelectedColor(v) { this.trackSelectedColor = v; this.UpdateDraw(); }
|
|
68
70
|
/** C# style builders: thumb diameter, track height, palette, thumb shadow. */
|
|
69
71
|
Look() {
|
|
70
72
|
switch (this.UsingControlStyle) {
|
|
@@ -278,5 +280,11 @@ export class SkiaSlider extends SkiaControl {
|
|
|
278
280
|
this.End = Math.min(this.Max, Math.max(low, value));
|
|
279
281
|
return true;
|
|
280
282
|
}
|
|
281
|
-
|
|
283
|
+
/**
|
|
284
|
+
* End between Min and Max, read as the number, or "20 – 80" in range mode; the step is the arrow key's. The name is
|
|
285
|
+
* the app's AccessibilityLabel only (C# used to make the value the name, drawnui-cross 6c).
|
|
286
|
+
*/
|
|
287
|
+
get AccessibilityValue() {
|
|
288
|
+
return { Now: this.end, Min: this.Min, Max: this.Max, Step: this.Step > 0 ? this.Step : (this.Max - this.Min) / 100, Text: this.EnableRange ? `${this.start} – ${this.end}` : "" };
|
|
289
|
+
}
|
|
282
290
|
}
|
|
@@ -86,6 +86,7 @@ export declare class SkiaSprite extends AnimatedFramesRenderer {
|
|
|
86
86
|
/** Transparent borders of a frame, scanned once (C# ScanFrameContentBounds over the bitmap alpha). */
|
|
87
87
|
private GetFrameContentBounds;
|
|
88
88
|
protected OnAnimatorUpdated(value: number): void;
|
|
89
|
+
protected NextChangeMs(value: number): number | undefined;
|
|
89
90
|
protected OnAnimatorSeeking(time: number): void;
|
|
90
91
|
protected OnAnimatorInitializing(): void;
|
|
91
92
|
protected ApplySpeed(): void;
|
|
@@ -227,6 +227,10 @@ export class SkiaSprite extends AnimatedFramesRenderer {
|
|
|
227
227
|
}
|
|
228
228
|
// ---- animator ----
|
|
229
229
|
OnAnimatorUpdated(value) { this.Seek(value); }
|
|
230
|
+
NextChangeMs(value) {
|
|
231
|
+
const fd = this.FrameDurationMs;
|
|
232
|
+
return fd > 0 ? (Math.floor(value / fd) + 1) * fd : undefined;
|
|
233
|
+
}
|
|
230
234
|
OnAnimatorSeeking(time) {
|
|
231
235
|
if (!this.SpriteSheet)
|
|
232
236
|
return;
|
|
@@ -10,6 +10,8 @@ import { SkiaLayout } from "./SkiaLayout";
|
|
|
10
10
|
* take the style defaults (C# SetStyleDefault).
|
|
11
11
|
*/
|
|
12
12
|
export declare abstract class SkiaToggle extends SkiaLayout {
|
|
13
|
+
/** Takes mouse hover unless ReceivesHover is set false (C# ReceivesHoverByDefault): switch, checkbox, radio button. */
|
|
14
|
+
protected ReceivesHoverByDefault(): boolean;
|
|
13
15
|
private controlStyle;
|
|
14
16
|
get ControlStyle(): PrebuiltControlStyle;
|
|
15
17
|
set ControlStyle(v: PrebuiltControlStyle);
|
|
@@ -8,6 +8,8 @@ import { SkiaLayout } from "./SkiaLayout";
|
|
|
8
8
|
* take the style defaults (C# SetStyleDefault).
|
|
9
9
|
*/
|
|
10
10
|
export class SkiaToggle extends SkiaLayout {
|
|
11
|
+
/** Takes mouse hover unless ReceivesHover is set false (C# ReceivesHoverByDefault): switch, checkbox, radio button. */
|
|
12
|
+
ReceivesHoverByDefault() { return true; }
|
|
11
13
|
controlStyle = "Unset";
|
|
12
14
|
get ControlStyle() { return this.controlStyle; }
|
|
13
15
|
set ControlStyle(v) {
|
|
@@ -83,7 +85,7 @@ export class SkiaToggle extends SkiaLayout {
|
|
|
83
85
|
RebuildDefaultContent() {
|
|
84
86
|
if (!this.contentCreated)
|
|
85
87
|
return;
|
|
86
|
-
this.
|
|
88
|
+
this.ClearChildren();
|
|
87
89
|
for (const p of this.stylePinned)
|
|
88
90
|
this[p] = -1;
|
|
89
91
|
this.stylePinned = [];
|