24 private bool _disposed;
25 private bool _isActive;
26 private float _elapsedSec;
27 private float _lifetimeSec = 1f;
28 private float _fadeInSec = 0.08f;
29 private float _fadeOutSec = 0.25f;
30 private long _lastAnimationTick;
31 private Func<Vector2> _sourceResolver;
49 Rectangle screenBounds,
51 string? nickname =
null)
55 screenBounds.Location,
58 ValidateBounds(screenBounds);
68 _sourceResolver = () =>
new Vector2(screenBounds.X, screenBounds.Y);
70 CompleteInitialization(
Content);
84 Rectangle worldBounds,
86 string? nickname =
null)
93 ValidateBounds(worldBounds);
103 _sourceResolver = () =>
new Vector2(worldBounds.X, worldBounds.Y);
105 CompleteInitialization(
Content);
124 Point? offsetPx =
null,
125 string? nickname =
null)
128 source?.
SceneLayer ?? throw new ArgumentNullException(nameof(source)),
129 new Rectangle(Point.Empty, size),
133 BindTo(source, sourceAnchor, offsetPx);
147 Rectangle screenBounds,
149 string? nickname =
null)
153 screenBounds.Location,
156 ArgumentNullException.ThrowIfNull(image);
157 ValidateBounds(screenBounds);
164 $
"{Nickname}.image");
167 _sourceResolver = () =>
new Vector2(screenBounds.X, screenBounds.Y);
169 CompleteInitialization(
Content);
183 Rectangle worldBounds,
185 string? nickname =
null)
189 worldBounds.Location,
192 ArgumentNullException.ThrowIfNull(image);
193 ValidateBounds(worldBounds);
200 $
"{Nickname}.image");
203 _sourceResolver = () =>
new Vector2(worldBounds.X, worldBounds.Y);
205 CompleteInitialization(
Content);
219 Rectangle screenBounds,
221 string? nickname =
null)
225 screenBounds.Location,
228 ArgumentNullException.ThrowIfNull(bitmap);
229 ValidateBounds(screenBounds);
236 $
"{Nickname}.image");
239 _sourceResolver = () =>
new Vector2(screenBounds.X, screenBounds.Y);
241 CompleteInitialization(
Content);
255 Rectangle worldBounds,
257 string? nickname =
null)
261 worldBounds.Location,
264 ArgumentNullException.ThrowIfNull(bitmap);
265 ValidateBounds(worldBounds);
272 $
"{Nickname}.image");
275 _sourceResolver = () =>
new Vector2(worldBounds.X, worldBounds.Y);
277 CompleteInitialization(
Content);
311 set => _lifetimeSec = value > 0f
313 :
throw new ArgumentOutOfRangeException(nameof(value));
322 set => _fadeInSec = value >= 0f
324 :
throw new ArgumentOutOfRangeException(nameof(value));
333 set => _fadeOutSec = value >= 0f
335 :
throw new ArgumentOutOfRangeException(nameof(value));
373 _sourceResolver = () =>
new Vector2(locationPx.X, locationPx.Y);
388 Point? offsetPx =
null)
390 ArgumentNullException.ThrowIfNull(source);
393 throw new InvalidOperationException(
"Only a scene-layer popup can bind to a tile.");
396 throw new ArgumentException(
"The source tile must belong to the popup's SceneLayer.", nameof(source));
398 Point offset = offsetPx ?? Point.Empty;
402 ? fixedTile.GridCoordinatesAbs
405 _sourceResolver = () => GetCenteredSourcePosition(
427 Point? offsetPx =
null)
429 ArgumentNullException.ThrowIfNull(sceneLayer);
432 ??
throw new ArgumentOutOfRangeException(nameof(gridLocation),
"The grid location is outside the SceneLayer.");
434 BindTo(tile, sourceAnchor, offsetPx);
447 throw new InvalidOperationException(
"This popup contains an image, not text.");
463 float? minSize =
null)
466 throw new InvalidOperationException(
"This popup contains an image, not text.");
468 Text.SetFont(typeface, size, minSize);
480 throw new InvalidOperationException(
"This popup contains an image, not text.");
482 Text.SetColors(color, SKColors.Transparent);
502 if (!_isActive || _disposed)
511 if (_disposed || tick <= _lastAnimationTick)
514 float elapsedSec = HighResTimer.GetDuration(_lastAnimationTick, tick);
515 _lastAnimationTick = tick;
522 _elapsedSec += elapsedSec;
533 opacity = Math.Clamp(_elapsedSec /
FadeInSec, 0f, 1f);
538 opacity = Math.Min(opacity, Math.Clamp(remainingSec /
FadeOutSec, 0f, 1f));
560 _lastAnimationTick = HighResTimer.GetCurrentTick();
575 base.ProcessHidden();
585 keepCurrentOffset:
false,
586 explicitLocalOffsetPx: Vector2.Zero);
592 private void CompletePopup()
601 private Size GetContentSize()
604 ? Content.ScreenBounds
610 private static Vector2 GetCenteredSourcePosition(
611 Rectangle sourceBounds,
616 PointF anchor = sourceAnchor.GetPoint(sourceBounds);
619 anchor.X - contentSize.Width / 2f + offsetPx.X,
620 anchor.Y - contentSize.Height / 2f + offsetPx.Y);
623 private static TextBlock CreateText(
624 RenderSurfaceHostBase host,
630 return new TextBlock(
636 .SetFont(SKTypeface.Default, 22f, minSize: 10f)
637 .SetColors(SKColors.White, SKColors.Transparent)
638 .SetAlignment(SKTextAlign.Center, TextBlock.VerticalAlign.Center)
639 .EnableWrapping(
false)
644 private static TextBlock CreateText(
645 RenderSurfaceHostBase host,
651 return new TextBlock(
658 .SetFont(SKTypeface.Default, 22f, minSize: 10f)
659 .SetColors(SKColors.White, SKColors.Transparent)
660 .SetAlignment(SKTextAlign.Center, TextBlock.VerticalAlign.Center)
661 .EnableWrapping(
false)
666 private static void ValidateBounds(Rectangle bounds)
668 if (bounds.Width <= 0 || bounds.Height <= 0)
669 throw new ArgumentOutOfRangeException(nameof(bounds),
"Popup bounds must have a positive width and height.");
SceneLayer? SceneLayer
Gets the scene layer shared by all children in scene-layer mode.
DirectComposite SetOpacity(float opacity)
Applies one opacity to every descendant.
DirectComposite SetIsVisible(bool visible)
Applies one visibility value to every descendant.
View? View
Gets the view shared by all children in view mode.
MovementController Movement
Gets the movement controller used to move the composite anchor.
virtual DirectComposite Add(IDirectCompositeChild child, bool keepCurrentOffset=true, Vector2? explicitLocalOffsetPx=null)
Adds a composite-compatible direct drawable as a child.
void SetPosition(Vector2 position)
Sets the composite anchor and repositions all children from their stored offsets.
DirectDrawingMode Mode
Gets the coordinate mode shared by the composite and its children.
Renders a bitmap or image to a rectangular region with support for scaling modes, source clipping,...
A retained-mode text drawable with wrapping, multi-line ( ) support, horizontal/vertical alignment,...
Represents an abstract base class for drawable tiles in the Gondwana engine. Provides core functional...
SceneLayer SceneLayer
Gets the scene layer that owns this tile.
Rectangle DrawLocationWorld
Gets the tile drawing bounds in world pixels.
Represents a base class for hosting a render surface, providing functionality for managing rendering ...
Represents the values stored at a single location on a SceneLayer.
Defines a movable direct drawable that may be owned by a DirectComposite.
Rectangle WorldBounds
The bounding rectangle of this drawable in WORLD space.
DirectDrawingMode
Specifies where direct drawing operations are applied within the rendering pipeline.
@ View
Performs direct drawing at the view level using screen-space coordinates.