16 private readonly HashSet<RadioButtonWidget> _buttons = [];
25 ArgumentNullException.ThrowIfNull(button);
34 ArgumentNullException.ThrowIfNull(button);
35 _buttons.Remove(button);
38 internal void Select(RadioButtonWidget selected)
40 ArgumentNullException.ThrowIfNull(selected);
42 foreach (RadioButtonWidget button
in _buttons.ToArray())
43 button.SetSelectedFromGroup(ReferenceEquals(button, selected));
52 private const int DefaultIndicatorSize = 20;
53 private const int DefaultLabelGap = 8;
54 private const int DotInset = 6;
56 private Color _normalColor = Color.FromArgb(255, 48, 48, 56);
57 private Color _hoverColor = Color.FromArgb(255, 66, 66, 76);
58 private Color _dotColor = Color.FromArgb(255, 235, 235, 242);
60 private bool _isSelected;
61 private bool _disposed;
83 bool isSelected =
false,
84 string? nickname =
null)
87 ArgumentNullException.ThrowIfNull(view);
89 Rectangle indicatorBounds = GetIndicatorBounds(bounds);
90 Rectangle dotBounds = GetDotBounds(indicatorBounds);
91 Rectangle labelBounds = GetLabelBounds(bounds, indicatorBounds.Width);
93 Ring = CreateRing(renderSurfaceHost, view, indicatorBounds);
94 Dot = CreateDot(renderSurfaceHost, view, dotBounds);
95 Label = CreateLabel(renderSurfaceHost, view, labelBounds, text);
101 CompleteInitialization(group, isSelected);
119 bool isSelected =
false,
120 string? nickname =
null)
123 ArgumentNullException.ThrowIfNull(sceneLayer);
125 Rectangle indicatorBounds = GetIndicatorBounds(bounds);
126 Rectangle dotBounds = GetDotBounds(indicatorBounds);
127 Rectangle labelBounds = GetLabelBounds(bounds, indicatorBounds.Width);
129 Ring = CreateRing(renderSurfaceHost, sceneLayer, indicatorBounds);
130 Dot = CreateDot(renderSurfaceHost, sceneLayer, dotBounds);
131 Label = CreateLabel(renderSurfaceHost, sceneLayer, labelBounds, text);
137 CompleteInitialization(group, isSelected);
163 if (ReferenceEquals(_group, value))
166 _group?.Unregister(
this);
168 _group?.Register(
this);
188 if (isSelected &&
Group is not
null)
194 SetSelectedFromGroup(isSelected);
214 Label.SetText(text ??
string.Empty);
229 _normalColor = normal;
233 UpdateRingColor(_normalColor);
234 Dot.SetColor(_dotColor);
246 Label.SetColors(color, SKColors.Transparent);
257 Ring.ZOrder = zOrder;
258 Dot.ZOrder = zOrder + 1;
259 Label.ZOrder = zOrder + 1;
284 base.OnPointerEnter(args);
285 UpdateRingColor(_hoverColor);
291 base.OnPointerLeave(args);
292 UpdateRingColor(_normalColor);
298 base.OnPointerClick(args);
310 base.OnKeyboardInput(args);
319 internal void SetSelectedFromGroup(
bool isSelected)
321 if (_isSelected == isSelected)
324 _isSelected = isSelected;
325 Dot.Visible = isSelected;
329 private void CompleteInitialization(RadioButtonGroup? group,
bool isSelected)
331 _isSelected = isSelected;
332 Dot.Visible = isSelected;
341 private void UpdateRingColor(Color color)
352 private DirectRectangle CreateRing(RenderSurfaceHostBase host,
356 return ConfigureRing(
new DirectRectangle(_normalColor, host, view, bounds, $
"{Nickname}.ring"), bounds.Width);
359 private DirectRectangle CreateRing(RenderSurfaceHostBase host,
363 return ConfigureRing(
new DirectRectangle(_normalColor, host, layer, bounds, $
"{Nickname}.ring"), bounds.Width);
366 private static DirectRectangle ConfigureRing(DirectRectangle ring,
int size)
374 private DirectRectangle CreateDot(RenderSurfaceHostBase host,
378 return ConfigureDot(
new DirectRectangle(_dotColor, host, view, bounds, $
"{Nickname}.dot"), bounds.Width);
381 private DirectRectangle CreateDot(RenderSurfaceHostBase host,
385 return ConfigureDot(
new DirectRectangle(_dotColor, host, layer, bounds, $
"{Nickname}.dot"), bounds.Width);
388 private static DirectRectangle ConfigureDot(DirectRectangle dot,
int size)
395 private static TextBlock CreateLabel(RenderSurfaceHostBase host,
400 return ConfigureLabel(
new TextBlock(host, view, bounds), text);
403 private static TextBlock CreateLabel(RenderSurfaceHostBase host,
408 return ConfigureLabel(
new TextBlock(host, layer, view:
null, worldBounds: bounds), text);
411 private static TextBlock ConfigureLabel(TextBlock label,
string text)
413 return label.
SetText(text ??
string.Empty)
414 .
SetFont(SKTypeface.Default, 16f, minSize: 10f)
415 .
SetColors(SKColors.White, SKColors.Transparent)
416 .
SetAlignment(SKTextAlign.Left, TextBlock.VerticalAlign.Center)
420 private static Rectangle GetIndicatorBounds(Rectangle bounds)
422 int size = Math.Min(DefaultIndicatorSize, Math.Max(10, bounds.Height - 2));
424 bounds.Y + (bounds.Height - size) / 2,
429 private static Rectangle GetDotBounds(Rectangle indicatorBounds)
431 int inset = Math.Min(DotInset, Math.Max(2, indicatorBounds.Width / 3));
432 return Rectangle.Inflate(indicatorBounds, -inset, -inset);
435 private static Rectangle GetLabelBounds(Rectangle bounds,
int indicatorWidth)
437 int left = bounds.X + indicatorWidth + DefaultLabelGap;
440 Math.Max(1, bounds.Right - left),
444 private static Rectangle ValidateBounds(Rectangle bounds)
446 if (bounds.Width < 40 || bounds.Height < 12)
447 throw new ArgumentOutOfRangeException(nameof(bounds), bounds,
"Radio-button bounds are too small.");
SceneLayer? SceneLayer
Gets the scene layer shared by all children in scene-layer mode.
View? View
Gets the view shared by all children in view mode.
virtual DirectComposite Add(IDirectCompositeChild child, bool keepCurrentOffset=true, Vector2? explicitLocalOffsetPx=null)
Adds a composite-compatible direct drawable as a child.
Vector2 GetPosition()
Gets the current position of this direct drawing in pixel coordinates.
void SetPosition(Vector2 p)
Sets the position of this direct drawing to the specified pixel coordinates.
Renders a configurable rectangle with support for fill, border, rounded corners, dash patterns,...
DirectRectangle SetFilled(bool isFilled)
Sets whether the rectangle interior is filled with the base color (or pattern).
DirectRectangle SetBorderColor(Color color)
Sets a distinct border (stroke) color, independent of the fill color.
DirectRectangle SetColor(Color color)
Sets the base color used for both fill and stroke (unless a distinct border color is specified).
DirectRectangle SetStrokeWidth(float width)
Sets the width (thickness) of the rectangle's stroke (outline) in pixels.
DirectRectangle SetCornerRadius(float radius)
Sets the radius for rounded corners in pixels.
A retained-mode text drawable with wrapping, multi-line ( ) support, horizontal/vertical alignment,...
TextBlock SetFont(SKTypeface typeface, float size, float? minSize=null)
Sets the font face and size (and optional minimum size for auto-shrink).
TextBlock EnableWrapping(bool enable=true)
Enables or disables word wrapping when laying out paragraphs.
TextBlock SetAlignment(SKTextAlign h, VerticalAlign v)
Sets the horizontal and vertical alignment used when drawing the laid-out lines within the bounds.
TextBlock SetColors(SKColor fg, SKColor bg)
Sets the foreground (text) and background colors using Skia colors.
TextBlock SetText(string text)
Sets the current text content and rebuilds layout as needed. If no reveal animation is active,...
Represents a base class for hosting a render surface, providing functionality for managing rendering ...
@ Rectangle
Particles are spawned uniformly within a rectangular area. This is the default distribution.
DirectDrawingMode
Specifies where direct drawing operations are applied within the rendering pipeline.