drawnui-react 0.1.0-preview.13 → 0.1.0-preview.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/SKIPPED.md +1 -1
- package/dist/controls/SkiaCarousel.js +4 -0
- package/dist/controls/SkiaScroll.js +10 -0
- package/dist/core/Canvas.d.ts +2 -0
- package/dist/core/Canvas.js +7 -2
- package/dist/core/Gestures.d.ts +5 -1
- package/dist/core/Gestures.js +4 -1
- package/dist/core/SkiaControl.d.ts +6 -1
- package/dist/core/SkiaControl.js +10 -2
- package/dist/core/SkiaEffect.d.ts +4 -0
- package/dist/core/SkiaEffect.js +16 -2
- package/package.json +2 -1
package/SKIPPED.md
CHANGED
|
@@ -77,7 +77,7 @@ DrawnUi name and semantics; nothing here is a redesign, only an omission.
|
|
|
77
77
|
| `SkiaImageManager` | partial | `Instance.LoadImageAsync(url, signal)` (direct), `LoadImageManagedAsync(url, signal, priority)` through the priority queue (High > Normal > Low, `MaxParallelLoads` 5 in flight like the C# semaphore, one fetch per url serves every requester), `PreloadImage` / `PreloadImages(urls, priority)`, `CancelAll`, `GetFromCache`, `CanReload` callback on failure, `QueuedCount` / `RunningCount`, `ReuseBitmaps`, `Clear()`; in-memory cache of decoded images only. No `CacheLongevitySecs` eviction, no platform loaders, no `LoadImageOnlineAsync` retry policy, no `ImageSource` types (urls only). |
|
|
78
78
|
| `SkiaImageTiles` | ported | `TileWidth` / `TileHeight` (points, nothing drawn until set), `TileAspect` (AspectCover), `TileOffsetX` / `TileOffsetY` (wrap), `TileCacheType` (Image) for the inner tile `SkiaImage` sharing the decoded source, clipped to bounds. |
|
|
79
79
|
| `SkiaSvg` | partial | Inline `SvgString` without `xmlns` gets it injected (browsers refuse to decode an `<img>` SVG without it, SkiaSharp does not care) — the C# check-mark markup relies on that. `Source` (URL) / `SvgString`, `Aspect` (default `AspectFitFill`, uses the shared `RescaleAspect` math, not SkiaSvg's own matrix path), alignments, `TintColor` (SrcIn), `Success`/`Error`, `IsLoading`, `DisplayRect`. Rendering: browser decodes the SVG, rasterized at the displayed pixel size and cached per size (CanvasKit npm has no SVG module). Not ported: shadows, FontAwesome duotone colors, `FillGradient`, `Zoom*`/offsets/`InflateAmount`, `IconFilePath`/embedded resources, `UseCache=Operations` default (no caching yet). |
|
|
80
|
-
| `SkiaScroll` | partial | `Orientation` Vertical/Horizontal/Both/Neither (Neither: pans never move the viewport, the wheel is not consumed so a parent scroll may take it; programmatic `ScrollTo` still works), single `Content`, `ViewportOffsetX/Y` (points, <= 0), pan with the C# 0.85 delta interpolation, fling on the DrawnUi deceleration curve (`FrictionScrolled`, `ChangeVelocityScrolled`, `MaxVelocity`, edge-cut duration), rubber-band overscroll (`Bounces`, `RubberEffect`) + spring bounce (`RubberDamping`, `MaxBounceVelocity`), mouse wheel (`WheelLineSize` per notch, an event moving by its share of a notch: `Canvas.WheelDeltaPerNotch` 100 CSS px after `deltaMode` lines x 40 / pages x 800, dominant axis, as the C# browser heads; `AutoScrollingSpeedMs` glide for a notch, an event under half a notch moves at once (touchpads, see PARITY); events accumulate onto the running move's exact target), `ScrollTo`/`ScrollToTop`/`ScrollToBottom`/`StopScrolling`, `Scrolled`, `IgnoreWrongDirection`, `RespondsToGestures`, `IsUserPanning`/`IsScrolling`, `ContentSize`, `ContentOffsetBounds`, `OverScrolled`. `Header` / `Footer` (JSX children with `Tag="Header"` / `Tag="Footer"`; the header scrolls in the flow, `HeaderSticky` pins it at the viewport start drawn over the content, `HeaderBehind` draws it under the content, `HeaderParallaxRatio` (1 = with the content, 0.5 = half speed), `ParallaxOverscrollEnabled`, `ContentOffset` between a behind / sticky header and the content; both add to the scroll extent), scroll bars (`ScrollBarsVisibility` None / Vertical / Horizontal / Both creating default `SkiaScrollBar`s, `ScrollBar` / `ScrollBarHorizontal` custom `IScrollBar` controls via `Tag="ScrollBar"` / `"ScrollBarHorizontal"`, `ScrollBarThumbColor` / `ScrollBarTrackColor`; `SkiaScrollBar`: `Dock`, `ThumbColor`, `TrackColor`, `Thickness` 4, `EdgeMargin` 2, `MinThumbSize` 32, `AutoHide` + `HideDelaySecs` 1 + `HideDurationSecs` 0.25, thumb squashed on overscroll, `IsDraggable` + `GrabPadding` 8: the scroll takes a gesture that starts on the bar from down to up, thumb drag keeps the grab point, a track press jumps the thumb under the pointer, the content gets neither the pan nor the tap; a custom `IScrollBar` opts in by implementing `IsDraggable` / `BeginDrag` / `GetDragProgress`; bars are parent-independent (C# `IsParentIndependent`): a thumb resize invalidates the bar alone and the scroll re-measures it on draw, nothing above re-measures), pull to refresh (`RefreshEnabled`, `RefreshCommand` callback, `IsRefreshing` two-way, `RefreshDistanceLimit` 150, `RefreshShowDistance` 50, `RefreshIndicator` `IRefreshIndicator` control via `Tag="RefreshIndicator"`; `RefreshIndicator` base: `Orientation`, `SetDragRatio` slides the view in with the pull and parks it at RefreshShowDistance, `IsRunning` + `OnIsRunningChanged`, `VisibleRatio`), `SnapToChildren` Center / Side after a fling or a release (`Snap`, `CheckNeedToSnap`), `TrackIndexPosition` Start / Center / End + `TrackIndexPositionOffset` reporting `CurrentIndex` / `CurrentIndexChanged`. Not ported: `ScrollToIndex` with `Center`/deferred ordered scroll for unmeasured indexes (Start/End on measured structures ported), zoom (`ViewportZoom`, `ZoomLocked`), `ReverseGestures` (inverted chat), keyboard adaptation, `ResetScrollPositionOnContentSizeChanged`, `ScrollType`, `ScrollingEnded` event, `LottieRefreshIndicator`, virtualization hooks (`Virtualisation`, `UseVirtual`, windowed content bounds); the C# refresh-indicator position curve is replaced by a linear slide-in. |
|
|
80
|
+
| `SkiaScroll` | partial | `Orientation` Vertical/Horizontal/Both/Neither (Neither: pans never move the viewport, the wheel is not consumed so a parent scroll may take it; programmatic `ScrollTo` still works), single `Content`, `ViewportOffsetX/Y` (points, <= 0), pan with the C# 0.85 delta interpolation, fling on the DrawnUi deceleration curve (`FrictionScrolled`, `ChangeVelocityScrolled`, `MaxVelocity`, edge-cut duration), rubber-band overscroll (`Bounces`, `RubberEffect`) + spring bounce (`RubberDamping`, `MaxBounceVelocity`), mouse wheel (`WheelLineSize` per notch, an event moving by its share of a notch: `Canvas.WheelDeltaPerNotch` 100 CSS px after `deltaMode` lines x 40 / pages x 800, dominant axis, as the C# browser heads; `AutoScrollingSpeedMs` glide for a notch, an event under half a notch moves at once (touchpads, see PARITY); events accumulate onto the running move's exact target, and a restarted glide starts at the event so a fast swipe moves on every frame; `Wheel.IsHorizontal`: a vertical scroll leaves horizontal events, a horizontal scroll takes both, C# ba03cb20), `ScrollTo`/`ScrollToTop`/`ScrollToBottom`/`StopScrolling`, `Scrolled`, `IgnoreWrongDirection`, `RespondsToGestures`, `IsUserPanning`/`IsScrolling`, `ContentSize`, `ContentOffsetBounds`, `OverScrolled`. `Header` / `Footer` (JSX children with `Tag="Header"` / `Tag="Footer"`; the header scrolls in the flow, `HeaderSticky` pins it at the viewport start drawn over the content, `HeaderBehind` draws it under the content, `HeaderParallaxRatio` (1 = with the content, 0.5 = half speed), `ParallaxOverscrollEnabled`, `ContentOffset` between a behind / sticky header and the content; both add to the scroll extent), scroll bars (`ScrollBarsVisibility` None / Vertical / Horizontal / Both creating default `SkiaScrollBar`s, `ScrollBar` / `ScrollBarHorizontal` custom `IScrollBar` controls via `Tag="ScrollBar"` / `"ScrollBarHorizontal"`, `ScrollBarThumbColor` / `ScrollBarTrackColor`; `SkiaScrollBar`: `Dock`, `ThumbColor`, `TrackColor`, `Thickness` 4, `EdgeMargin` 2, `MinThumbSize` 32, `AutoHide` + `HideDelaySecs` 1 + `HideDurationSecs` 0.25, thumb squashed on overscroll, `IsDraggable` + `GrabPadding` 8: the scroll takes a gesture that starts on the bar from down to up, thumb drag keeps the grab point, a track press jumps the thumb under the pointer, the content gets neither the pan nor the tap; a custom `IScrollBar` opts in by implementing `IsDraggable` / `BeginDrag` / `GetDragProgress`; bars are parent-independent (C# `IsParentIndependent`): a thumb resize invalidates the bar alone and the scroll re-measures it on draw, nothing above re-measures), pull to refresh (`RefreshEnabled`, `RefreshCommand` callback, `IsRefreshing` two-way, `RefreshDistanceLimit` 150, `RefreshShowDistance` 50, `RefreshIndicator` `IRefreshIndicator` control via `Tag="RefreshIndicator"`; `RefreshIndicator` base: `Orientation`, `SetDragRatio` slides the view in with the pull and parks it at RefreshShowDistance, `IsRunning` + `OnIsRunningChanged`, `VisibleRatio`), `SnapToChildren` Center / Side after a fling or a release (`Snap`, `CheckNeedToSnap`), `TrackIndexPosition` Start / Center / End + `TrackIndexPositionOffset` reporting `CurrentIndex` / `CurrentIndexChanged`. Not ported: `ScrollToIndex` with `Center`/deferred ordered scroll for unmeasured indexes (Start/End on measured structures ported), zoom (`ViewportZoom`, `ZoomLocked`), `ReverseGestures` (inverted chat), keyboard adaptation, `ResetScrollPositionOnContentSizeChanged`, `ScrollType`, `ScrollingEnded` event, `LottieRefreshIndicator`, virtualization hooks (`Virtualisation`, `UseVirtual`, windowed content bounds); the C# refresh-indicator position curve is replaced by a linear slide-in. |
|
|
81
81
|
| `SkiaShape` (+ `SkiaFrame`) | partial | `BevelType` Bevel / Emboss + `Bevel` (`Depth`, `LightColor`, `ShadowColor`, `Opacity`; C# `PaintBevelEffect` edge paths for Rectangle, rounded Rectangle, Circle/Ellipse, Polygon, Path via ContourMeasure halves). `Shadows` (`SkiaShadow` X/Y/Blur/Opacity/Color/ShadowOnly, plain literals accepted): fill painted once per shadow with a DropShadow image filter (C# `PaintWithShadowsInternal`), hollow shapes clip their outline away so only the outside shadow remains; caches record the effects margin (`3·Blur·scale ± offset`, C# `MergeShadowMargin`) via `ComputeEffectsMargin`/`ExpandedCacheRect`. Not ported: `PlatformShadow` (MAUI `Shadow` brush), `ExpandDirtyRegion`, bevel/emboss. `Type` Rectangle/Circle/Ellipse/Arc (`Value1` start, `Value2` sweep)/Polygon+Line (`Points` ratios)/Path (`PathData`, fitted + centered), `CornerRadius` (uniform or per-corner), `StrokeWidth` (points, negative = px) drawn inside the bounds, `StrokeColor`, `StrokeCap`, `ClipBackgroundColor`, children laid out inside the stroke and clipped to the shape, `CreateClip` = shape, `FillGradient` fill, `UseCache=Operations` default. Not ported: `Squricle`, `Custom`, `SmoothPoints`, `StrokePath` (dashes), `StrokeGradient`, `StrokeBlendMode`, sub-1px stroke compensation, `MeasuredStrokeAware*` exposure, `LayoutChildren` override hook. |
|
|
82
82
|
| `SkiaButton` | partial | Now a `SkiaLayout` hosting a `SkiaShape` frame (`Tag="BtnShape"`) + `SkiaLabel` (`Tag="BtnText"`), sized from the label + Padding; `CornerRadius` (default 8), `StrokeColor`/`StrokeWidth`, `BackgroundColor`, text props, `ApplyEffect`, `Tapped`/`Down`/`Up`. Still no `ButtonStyle` looks, icons, `TextCase`, elevation, shimmer, custom templating through tags. |
|
|
83
83
|
| `SnappingLayout` | ported | `Animated`, `RespondsToGestures`, `IgnoreWrongDirection`, `Bounces`, `RubberDamping`, `RubberEffect`, `AutoVelocityMultiplyPts`, `SnapDistanceRatio`, `SnapPoints`, `CurrentPosition`, `CurrentSnap`, `ContentOffsetBounds`, `IsUserPanning`/`IsUserFocused`, `InTransition`, `Scrolled`/`TransitionChanged`/`Stopped`, `ClampOffset` (rubber), `FindNearestAnchor`, `SelectNextAnchor` (dot product), `ScrollToNearestAnchor`, `ScrollToOffset` (spring `Spring(1+RubberDamping, 200, 0.5·(1+RubberDamping))` when `Bounces`, else 0.1–0.8 s from velocity). The settled state is reported when the snap animation stops (C# relies on `ApplyPosition` ticks). Not ported: `AnimatorSpring` reuse, `SnapDistanceRatio` for non-carousel layouts, hover. |
|
|
@@ -561,6 +561,10 @@ export class SkiaCarousel extends SnappingLayout {
|
|
|
561
561
|
if (!this.IsUserPanning) {
|
|
562
562
|
const movex = Math.abs(e.Distance.Total.X), movey = Math.abs(e.Distance.Total.Y);
|
|
563
563
|
const along = this.IsVertical ? movey : movex, across = this.IsVertical ? movex : movey;
|
|
564
|
+
// a first move too short to tell the direction decides nothing yet (a 1 CSS px move at devicePixelRatio 2):
|
|
565
|
+
// marking it wrong kept the whole drag dead until the next press (DrawnUi.Rust c6b22e3; C# decides on every move)
|
|
566
|
+
if (along < scale * 2 && across < scale * 2)
|
|
567
|
+
return consumedDefault;
|
|
564
568
|
if (along < scale * 2 || across > along) {
|
|
565
569
|
this.wrongDirection = true;
|
|
566
570
|
return consumedDefault;
|
|
@@ -901,6 +901,9 @@ export class SkiaScroll extends SkiaControl {
|
|
|
901
901
|
return child;
|
|
902
902
|
if (!this.RespondsToGestures || this.Orientation === "Neither")
|
|
903
903
|
return child ?? consumedDefault; // Neither: not used, a parent scroll may take it
|
|
904
|
+
// a vertical scroll leaves horizontal events (the sideways part of a diagonal swipe) to whatever is around it
|
|
905
|
+
if (e.Wheel.IsHorizontal && this.Orientation === "Vertical")
|
|
906
|
+
return child ?? consumedDefault;
|
|
904
907
|
if (!this.ApplyWheelScroll(e.Wheel.Delta))
|
|
905
908
|
return consumedDefault; // at its edge: not used, the page may take it
|
|
906
909
|
e.Handled = true;
|
|
@@ -1069,6 +1072,13 @@ export class SkiaScroll extends SkiaControl {
|
|
|
1069
1072
|
// content behind the fingers, a visible delay before it started to move
|
|
1070
1073
|
const glide = perNotch <= 0 || Math.abs(delta) >= perNotch / 2;
|
|
1071
1074
|
this.ScrollTo(x, y, glide ? this.AutoScrollingSpeedMs / 1000 : 0, true);
|
|
1075
|
+
// a restarted glide starts at the event, not at its first frame: a fast trackpad swipe sends a notch-sized event
|
|
1076
|
+
// before every frame, and a glide drawn at progress 0 on each of them left the content standing still until the
|
|
1077
|
+
// events stopped, then it jumped (DrawnUi.Rust dfe36fe). Never before the last frame, at most one frame back.
|
|
1078
|
+
if (glide && running.IsRunning) {
|
|
1079
|
+
const event = performance.now() * 1_000_000;
|
|
1080
|
+
running.StartFrameTimeNanos = running.LastFrameTimeNanos = Math.max(this.Superview?.FrameTimeNanos ?? 0, event - 16_666_667);
|
|
1081
|
+
}
|
|
1072
1082
|
return true;
|
|
1073
1083
|
}
|
|
1074
1084
|
}
|
package/dist/core/Canvas.d.ts
CHANGED
|
@@ -83,6 +83,8 @@ export declare class Canvas {
|
|
|
83
83
|
* fingers moved. 0 = units unknown: every event scrolls one line.
|
|
84
84
|
*/
|
|
85
85
|
WheelDeltaPerNotch: number;
|
|
86
|
+
/** Vsync time of the last frame the animators ran on (nanoseconds, the performance.now() timeline). */
|
|
87
|
+
FrameTimeNanos: number;
|
|
86
88
|
/** On-screen surface (SkiaBackdrop snapshots it). */
|
|
87
89
|
get Surface(): Surface | undefined;
|
|
88
90
|
/**
|
package/dist/core/Canvas.js
CHANGED
|
@@ -140,6 +140,7 @@ export class Canvas {
|
|
|
140
140
|
// (measured 12..23 ms between frames shown 16.7 ms apart), and a game loop moving by speed * delta then
|
|
141
141
|
// jumps unevenly on screen.
|
|
142
142
|
const frameTime = Number(document.timeline?.currentTime ?? started);
|
|
143
|
+
this.FrameTimeNanos = Math.round(frameTime * 1_000_000);
|
|
143
144
|
const executed = this.ExecuteAnimators(Math.round(frameTime * 1_000_000));
|
|
144
145
|
const canRender = this.CanRender;
|
|
145
146
|
if (canRender && !this.WasRendered)
|
|
@@ -209,6 +210,8 @@ export class Canvas {
|
|
|
209
210
|
* fingers moved. 0 = units unknown: every event scrolls one line.
|
|
210
211
|
*/
|
|
211
212
|
WheelDeltaPerNotch = 100;
|
|
213
|
+
/** Vsync time of the last frame the animators ran on (nanoseconds, the performance.now() timeline). */
|
|
214
|
+
FrameTimeNanos = 0;
|
|
212
215
|
/** On-screen surface (SkiaBackdrop snapshots it). */
|
|
213
216
|
get Surface() { return this.surface; }
|
|
214
217
|
/**
|
|
@@ -389,9 +392,11 @@ export class Canvas {
|
|
|
389
392
|
args.Scale = this.RenderingScale;
|
|
390
393
|
args.Location = new SKPoint((e.clientX - rect.left) * this.RenderingScale, (e.clientY - rect.top) * this.RenderingScale);
|
|
391
394
|
args.StartingLocation = args.Location;
|
|
392
|
-
// lines and pages to pixels, then the dominant axis (the .NET browser heads, fc8980c1)
|
|
395
|
+
// lines and pages to pixels, then the dominant axis (the .NET browser heads, fc8980c1); a vertical scroll leaves
|
|
396
|
+
// horizontal events alone (C# ba03cb20)
|
|
393
397
|
const factor = e.deltaMode === 1 ? 40 : e.deltaMode === 2 ? 800 : 1;
|
|
394
|
-
|
|
398
|
+
const horizontal = Math.abs(e.deltaX) > Math.abs(e.deltaY);
|
|
399
|
+
args.Wheel = { Delta: (horizontal ? e.deltaX : e.deltaY) * factor, IsHorizontal: horizontal };
|
|
395
400
|
if (this.gestures === "Lock") {
|
|
396
401
|
e.preventDefault();
|
|
397
402
|
this.OnGestureEvent(args, "Wheel");
|
package/dist/core/Gestures.d.ts
CHANGED
|
@@ -49,9 +49,13 @@ export declare class TouchActionEventArgs {
|
|
|
49
49
|
Timestamp: number;
|
|
50
50
|
/** ms since the previous event of the same pointer. */
|
|
51
51
|
DeltaTimeMs: number;
|
|
52
|
-
/**
|
|
52
|
+
/**
|
|
53
|
+
* Mouse wheel: Delta > 0 = wheel down / right (browser sign). IsHorizontal: the event is along the X axis (a tilting
|
|
54
|
+
* wheel, the sideways part of a two-finger touchpad swipe), as C# WheelEventArgs.IsHorizontal.
|
|
55
|
+
*/
|
|
53
56
|
Wheel: {
|
|
54
57
|
Delta: number;
|
|
58
|
+
IsHorizontal?: boolean;
|
|
55
59
|
};
|
|
56
60
|
/**
|
|
57
61
|
* AppoMobi TouchActionEventArgs.Handled: set by a control that actually used the event. The canvas prevents the
|
package/dist/core/Gestures.js
CHANGED
|
@@ -43,7 +43,10 @@ export class TouchActionEventArgs {
|
|
|
43
43
|
Timestamp = performance.now();
|
|
44
44
|
/** ms since the previous event of the same pointer. */
|
|
45
45
|
DeltaTimeMs = 0;
|
|
46
|
-
/**
|
|
46
|
+
/**
|
|
47
|
+
* Mouse wheel: Delta > 0 = wheel down / right (browser sign). IsHorizontal: the event is along the X axis (a tilting
|
|
48
|
+
* wheel, the sideways part of a two-finger touchpad swipe), as C# WheelEventArgs.IsHorizontal.
|
|
49
|
+
*/
|
|
47
50
|
Wheel = { Delta: 0 };
|
|
48
51
|
/**
|
|
49
52
|
* AppoMobi TouchActionEventArgs.Handled: set by a control that actually used the event. The canvas prevents the
|
|
@@ -181,7 +181,12 @@ export declare class SkiaControl {
|
|
|
181
181
|
protected OnVisualEffectsChanged(): void;
|
|
182
182
|
/** Post renderers that can render this frame (compiled shaders); an unready effect leaves the control drawn plainly. */
|
|
183
183
|
private ActivePostRenderers;
|
|
184
|
-
/**
|
|
184
|
+
/**
|
|
185
|
+
* C# CachedImage: the cached texture (Image caches only) and the canvas rect it covers NOW. Scrolled content is
|
|
186
|
+
* re-arranged here, not drawn through a translated canvas, so a cache recorded before its control moved is blitted
|
|
187
|
+
* at the control's current aligned rect (RenderContent) and its record-time Bounds are stale: an effect sampling it
|
|
188
|
+
* there (the slides of a SkiaShaderCarousel after the page scrolled) was off by the scroll amount.
|
|
189
|
+
*/
|
|
185
190
|
get CachedImage(): CachedTexture | undefined;
|
|
186
191
|
/** Clip overlay effects to the control's shape (CreateClip). */
|
|
187
192
|
ClipEffects: boolean;
|
package/dist/core/SkiaControl.js
CHANGED
|
@@ -235,10 +235,18 @@ export class SkiaControl {
|
|
|
235
235
|
return [];
|
|
236
236
|
return this.EffectPostRenderers.filter((e) => e.NeedApply);
|
|
237
237
|
}
|
|
238
|
-
/**
|
|
238
|
+
/**
|
|
239
|
+
* C# CachedImage: the cached texture (Image caches only) and the canvas rect it covers NOW. Scrolled content is
|
|
240
|
+
* re-arranged here, not drawn through a translated canvas, so a cache recorded before its control moved is blitted
|
|
241
|
+
* at the control's current aligned rect (RenderContent) and its record-time Bounds are stale: an effect sampling it
|
|
242
|
+
* there (the slides of a SkiaShaderCarousel after the page scrolled) was off by the scroll amount.
|
|
243
|
+
*/
|
|
239
244
|
get CachedImage() {
|
|
240
245
|
const c = this.RenderObject;
|
|
241
|
-
|
|
246
|
+
if (!c?.Image)
|
|
247
|
+
return undefined;
|
|
248
|
+
const r = this.AlignedCacheRect(c.Scale);
|
|
249
|
+
return { Image: c.Image, Bounds: SKRect.Create(r.Left, r.Top, c.Bounds.Width, c.Bounds.Height) };
|
|
242
250
|
}
|
|
243
251
|
/** Clip overlay effects to the control's shape (CreateClip). */
|
|
244
252
|
ClipEffects = true;
|
|
@@ -125,6 +125,10 @@ export declare class SkiaShaderEffect extends SkiaEffect implements IPostRendere
|
|
|
125
125
|
protected ApplyShaderSource(): void;
|
|
126
126
|
/** Snapshot of what the parent painted (C# CreateSnapshot): the surface the pixels are on, mapped through its origin. */
|
|
127
127
|
protected CreateSnapshot(ctx: DrawingContext, destination: SKRect): CachedTexture | undefined;
|
|
128
|
+
/** Where the parent was when the texture was frozen (Once): the texture moves with it, as its cache does. */
|
|
129
|
+
private frozenAt?;
|
|
130
|
+
private ParentOrigin;
|
|
131
|
+
private FollowParent;
|
|
128
132
|
/** C# GetPrimaryTexture: the parent's cache, a frozen snapshot (Once) or nothing (Never). */
|
|
129
133
|
protected GetPrimaryTexture(_ctx: DrawingContext, _destination: SKRect): CachedTexture | undefined;
|
|
130
134
|
/** Image → shader with the effect's sampling, translated so texel (0,0) = bounds top-left; cached per image. */
|
package/dist/core/SkiaEffect.js
CHANGED
|
@@ -2,7 +2,7 @@ import { SkiaValueAnimator } from "./Animators";
|
|
|
2
2
|
import { Easing } from "./Easing";
|
|
3
3
|
import { SkiaImageManager } from "./SkiaImageManager";
|
|
4
4
|
import { Super } from "./Super";
|
|
5
|
-
import { Thickness } from "./Types";
|
|
5
|
+
import { SKRect, Thickness } from "./Types";
|
|
6
6
|
/**
|
|
7
7
|
* Mirrors DrawnUi SkiaEffect: something attached to a control through `VisualEffects`. `Update()` re-renders the
|
|
8
8
|
* parent (C# invalidates the parent's cache and redraws), `GetEffectMargin` reports what it paints outside the box.
|
|
@@ -129,6 +129,7 @@ export class SkiaShaderEffect extends SkiaEffect {
|
|
|
129
129
|
this.DisposeImage(this.frozen.Image);
|
|
130
130
|
this.frozen = undefined;
|
|
131
131
|
this.frozenOwned = false;
|
|
132
|
+
this.frozenAt = undefined;
|
|
132
133
|
}
|
|
133
134
|
DisposeImage(image) {
|
|
134
135
|
const sv = this.Parent?.Superview;
|
|
@@ -158,6 +159,18 @@ export class SkiaShaderEffect extends SkiaEffect {
|
|
|
158
159
|
return undefined;
|
|
159
160
|
return { Image: image, Bounds: destination, Origin: { X: ox, Y: oy } };
|
|
160
161
|
}
|
|
162
|
+
/** Where the parent was when the texture was frozen (Once): the texture moves with it, as its cache does. */
|
|
163
|
+
frozenAt;
|
|
164
|
+
ParentOrigin() { const r = this.Parent?.DrawingRect; return { X: r?.Left ?? 0, Y: r?.Top ?? 0 }; }
|
|
165
|
+
FollowParent(texture) {
|
|
166
|
+
if (!texture || !this.frozenAt)
|
|
167
|
+
return texture;
|
|
168
|
+
const now = this.ParentOrigin(), dx = now.X - this.frozenAt.X, dy = now.Y - this.frozenAt.Y;
|
|
169
|
+
if (dx === 0 && dy === 0)
|
|
170
|
+
return texture;
|
|
171
|
+
const b = texture.Bounds;
|
|
172
|
+
return { Image: texture.Image, Bounds: new SKRect(b.Left + dx, b.Top + dy, b.Right + dx, b.Bottom + dy), Origin: texture.Origin && { X: texture.Origin.X + dx, Y: texture.Origin.Y + dy } };
|
|
173
|
+
}
|
|
161
174
|
/** C# GetPrimaryTexture: the parent's cache, a frozen snapshot (Once) or nothing (Never). */
|
|
162
175
|
GetPrimaryTexture(_ctx, _destination) {
|
|
163
176
|
switch (this.UseBackground) {
|
|
@@ -175,9 +188,10 @@ export class SkiaShaderEffect extends SkiaEffect {
|
|
|
175
188
|
this.frozen = snapshot;
|
|
176
189
|
this.frozenOwned = owned;
|
|
177
190
|
this.AquiredBackground = true;
|
|
191
|
+
this.frozenAt = this.ParentOrigin();
|
|
178
192
|
}
|
|
179
193
|
}
|
|
180
|
-
return this.frozen;
|
|
194
|
+
return this.FollowParent(this.frozen);
|
|
181
195
|
default:
|
|
182
196
|
return this.Parent?.CachedImage;
|
|
183
197
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "drawnui-react",
|
|
3
|
-
"version": "0.1.0-preview.
|
|
3
|
+
"version": "0.1.0-preview.14",
|
|
4
4
|
"description": "DrawnUi for React: the DrawnUi (.NET) drawn-UI engine in TypeScript on CanvasKit (Skia WASM). Same controls, same PascalCase API as DrawnUi.Net.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Nick Kovalsky (AppoMobi)",
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
"sync:skills": "node dev/sync-skills.mjs",
|
|
56
56
|
"check:recycling": "node dev/check.mjs dev/check-recycling.ts",
|
|
57
57
|
"check:keyboard": "node dev/check.mjs dev/check-keyboard.ts",
|
|
58
|
+
"check:wheel": "node dev/check.mjs dev/check-wheel.ts",
|
|
58
59
|
"site:extras": "node dev/site-extras.mjs dist/demo",
|
|
59
60
|
"build:lib": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.build.json",
|
|
60
61
|
"prepublishOnly": "npm run build:lib",
|