Gondwana Game Engine Development (master) - 2.6.1
Gondwana is a cross-platform 2.5D game and rendering engine written in C#/.NET 8. It provides fine-grained control over rendering, timing, and scene composition, with built-in support for parallax, z-ordering, pixel overhang, collision detection, and particle effects. Gondwana targets desktop and web platforms using SkiaSharp for graphics and pluggable audio backends for desktop and browser targets.
Loading...
Searching...
No Matches
CheckBoxWidget.cs
1using System.Drawing;
7using SkiaSharp;
8
10
14public sealed class CheckBoxWidget : WidgetBase
15{
16 private const int DefaultIndicatorSize = 20;
17 private const int DefaultLabelGap = 8;
18 private const int MarkInset = 5;
19
20 private Color _normalColor = Color.FromArgb(255, 48, 48, 56);
21 private Color _hoverColor = Color.FromArgb(255, 66, 66, 76);
22 private Color _markColor = Color.FromArgb(255, 235, 235, 242);
23 private bool _isChecked;
24
28 public event Action<bool>? CheckedChanged;
29
39 public CheckBoxWidget(RenderSurfaceHostBase renderSurfaceHost,
40 View view,
41 Rectangle bounds,
42 string text,
43 bool isChecked = false,
44 string? nickname = null)
45 : base(renderSurfaceHost, DirectDrawingMode.View, ValidateBounds(bounds).Location, nickname)
46 {
47 ArgumentNullException.ThrowIfNull(view);
48
49 Rectangle indicatorBounds = GetIndicatorBounds(bounds);
50 Rectangle markBounds = GetMarkBounds(indicatorBounds);
51 Rectangle labelBounds = GetLabelBounds(bounds, indicatorBounds.Width);
52
53 Box = CreateBox(renderSurfaceHost, view, indicatorBounds);
54 Mark = CreateMark(renderSurfaceHost, view, markBounds);
55 Label = CreateLabel(renderSurfaceHost, view, labelBounds, text);
56
57 Add(Box);
58 Add(Mark);
59 Add(Label);
60
61 CompleteInitialization(isChecked);
62 }
63
73 public CheckBoxWidget(RenderSurfaceHostBase renderSurfaceHost,
74 SceneLayer sceneLayer,
75 Rectangle bounds,
76 string text,
77 bool isChecked = false,
78 string? nickname = null)
79 : base(renderSurfaceHost, DirectDrawingMode.SceneLayer, ValidateBounds(bounds).Location, nickname)
80 {
81 ArgumentNullException.ThrowIfNull(sceneLayer);
82
83 Rectangle indicatorBounds = GetIndicatorBounds(bounds);
84 Rectangle markBounds = GetMarkBounds(indicatorBounds);
85 Rectangle labelBounds = GetLabelBounds(bounds, indicatorBounds.Width);
86
87 Box = CreateBox(renderSurfaceHost, sceneLayer, indicatorBounds);
88 Mark = CreateMark(renderSurfaceHost, sceneLayer, markBounds);
89 Label = CreateLabel(renderSurfaceHost, sceneLayer, labelBounds, text);
90
91 Add(Box);
92 Add(Mark);
93 Add(Label);
94
95 CompleteInitialization(isChecked);
96 }
97
101 public DirectRectangle Box { get; }
102
106 public DirectRectangle Mark { get; }
107
111 public TextBlock Label { get; }
112
116 public bool IsChecked
117 {
118 get => _isChecked;
119 set => SetChecked(value);
120 }
121
125 public Rectangle Bounds
126 {
127 get
128 {
129 Rectangle boxBounds = Mode == DirectDrawingMode.View ? Box.ScreenBounds : Box.WorldBounds;
130 Rectangle labelBounds = Mode == DirectDrawingMode.View ? Label.ScreenBounds : Label.WorldBounds;
131 return Rectangle.Union(boxBounds, labelBounds);
132 }
133 }
134
140 public CheckBoxWidget SetChecked(bool isChecked)
141 {
142 if (_isChecked == isChecked)
143 return this;
144
145 _isChecked = isChecked;
146 Mark.Visible = isChecked;
147 CheckedChanged?.Invoke(isChecked);
148 return this;
149 }
150
156 {
157 return SetChecked(!IsChecked);
158 }
159
165 public CheckBoxWidget SetText(string text)
166 {
167 Label.SetText(text ?? string.Empty);
168 return this;
169 }
170
178 public CheckBoxWidget SetColors(Color normal,
179 Color hover,
180 Color mark)
181 {
182 _normalColor = normal;
183 _hoverColor = hover;
184 _markColor = mark;
185
186 UpdateBoxColor(IsFocused ? _hoverColor : _normalColor);
187 Mark.SetColor(_markColor);
188 Refresh(Mark);
189 return this;
190 }
191
197 public CheckBoxWidget SetTextColor(SKColor color)
198 {
199 Label.SetColors(color, SKColors.Transparent);
200 return this;
201 }
202
209 {
210 Box.ZOrder = zOrder;
211 Mark.ZOrder = zOrder + 1;
212 Label.ZOrder = zOrder + 1;
213 return this;
214 }
215
217 protected override void ProcessShown()
218 {
219 base.ProcessShown();
220 Mark.Visible = IsChecked;
221 }
222
224 protected override void OnPointerEnter(WidgetPointerEventArgs args)
225 {
226 base.OnPointerEnter(args);
227 UpdateBoxColor(_hoverColor);
228 }
229
231 protected override void OnPointerLeave(WidgetPointerEventArgs args)
232 {
233 base.OnPointerLeave(args);
234 UpdateBoxColor(_normalColor);
235 }
236
238 protected override void OnPointerClick(WidgetPointerEventArgs args)
239 {
240 base.OnPointerClick(args);
241
242 if (!args.IsPrimaryButton)
243 return;
244
245 args.Handled = true;
246 Toggle();
247 }
248
250 protected override void OnKeyboardInput(WidgetKeyboardEventArgs args)
251 {
252 base.OnKeyboardInput(args);
253
254 if (args.KeyAction != KeyAction.Pressed || args.Key != 32)
255 return;
256
257 args.Handled = true;
258 Toggle();
259 }
260
261 private void CompleteInitialization(bool isChecked)
262 {
263 _isChecked = isChecked;
264 Mark.Visible = isChecked;
266
267 CanReceiveFocus = true;
269 }
270
271 private void UpdateBoxColor(Color color)
272 {
273 Box.SetColor(color);
274 Refresh(Box);
275 }
276
277 private static void Refresh(DirectRectangle rectangle)
278 {
279 rectangle.SetPosition(rectangle.GetPosition());
280 }
281
282 private DirectRectangle CreateBox(RenderSurfaceHostBase host,
283 View view,
284 Rectangle bounds)
285 {
286 return ConfigureBox(new DirectRectangle(_normalColor, host, view, bounds, $"{Nickname}.box"));
287 }
288
289 private DirectRectangle CreateBox(RenderSurfaceHostBase host,
290 SceneLayer layer,
291 Rectangle bounds)
292 {
293 return ConfigureBox(new DirectRectangle(_normalColor, host, layer, bounds, $"{Nickname}.box"));
294 }
295
296 private static DirectRectangle ConfigureBox(DirectRectangle box)
297 {
298 return box.SetFilled(true)
299 .SetBorderColor(Color.FromArgb(255, 150, 150, 160))
300 .SetStrokeWidth(1.5f)
301 .SetCornerRadius(3f);
302 }
303
304 private DirectRectangle CreateMark(RenderSurfaceHostBase host,
305 View view,
306 Rectangle bounds)
307 {
308 return ConfigureMark(new DirectRectangle(_markColor, host, view, bounds, $"{Nickname}.mark"));
309 }
310
311 private DirectRectangle CreateMark(RenderSurfaceHostBase host,
312 SceneLayer layer,
313 Rectangle bounds)
314 {
315 return ConfigureMark(new DirectRectangle(_markColor, host, layer, bounds, $"{Nickname}.mark"));
316 }
317
318 private static DirectRectangle ConfigureMark(DirectRectangle mark)
319 {
320 return mark.SetFilled(true)
321 .SetStrokeWidth(0f)
322 .SetCornerRadius(2f);
323 }
324
325 private static TextBlock CreateLabel(RenderSurfaceHostBase host,
326 View view,
327 Rectangle bounds,
328 string text)
329 {
330 return ConfigureLabel(new TextBlock(host, view, bounds), text);
331 }
332
333 private static TextBlock CreateLabel(RenderSurfaceHostBase host,
334 SceneLayer layer,
335 Rectangle bounds,
336 string text)
337 {
338 return ConfigureLabel(new TextBlock(host, layer, view: null, worldBounds: bounds), text);
339 }
340
341 private static TextBlock ConfigureLabel(TextBlock label, string text)
342 {
343 return label.SetText(text ?? string.Empty)
344 .SetFont(SKTypeface.Default, 16f, minSize: 10f)
345 .SetColors(SKColors.White, SKColors.Transparent)
346 .SetAlignment(SKTextAlign.Left, TextBlock.VerticalAlign.Center)
347 .EnableWrapping(false);
348 }
349
350 private static Rectangle GetIndicatorBounds(Rectangle bounds)
351 {
352 int size = Math.Min(DefaultIndicatorSize, Math.Max(10, bounds.Height - 2));
353 return new Rectangle(bounds.X,
354 bounds.Y + (bounds.Height - size) / 2,
355 size,
356 size);
357 }
358
359 private static Rectangle GetMarkBounds(Rectangle indicatorBounds)
360 {
361 int inset = Math.Min(MarkInset, Math.Max(2, indicatorBounds.Width / 4));
362 return Rectangle.Inflate(indicatorBounds, -inset, -inset);
363 }
364
365 private static Rectangle GetLabelBounds(Rectangle bounds, int indicatorWidth)
366 {
367 int left = bounds.X + indicatorWidth + DefaultLabelGap;
368 return new Rectangle(left,
369 bounds.Y,
370 Math.Max(1, bounds.Right - left),
371 bounds.Height);
372 }
373
374 private static Rectangle ValidateBounds(Rectangle bounds)
375 {
376 if (bounds.Width < 40 || bounds.Height < 12)
377 throw new ArgumentOutOfRangeException(nameof(bounds), bounds, "Checkbox bounds are too small.");
378
379 return bounds;
380 }
381}
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.
DirectDrawingMode Mode
Gets the coordinate mode shared by the composite and its children.
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,...
Definition TextBlock.cs:44
TextBlock SetFont(SKTypeface typeface, float size, float? minSize=null)
Sets the font face and size (and optional minimum size for auto-shrink).
Definition TextBlock.cs:394
TextBlock EnableWrapping(bool enable=true)
Enables or disables word wrapping when laying out paragraphs.
Definition TextBlock.cs:503
TextBlock SetAlignment(SKTextAlign h, VerticalAlign v)
Sets the horizontal and vertical alignment used when drawing the laid-out lines within the bounds.
Definition TextBlock.cs:433
TextBlock SetColors(SKColor fg, SKColor bg)
Sets the foreground (text) and background colors using Skia colors.
Definition TextBlock.cs:410
TextBlock SetText(string text)
Sets the current text content and rebuilds layout as needed. If no reveal animation is active,...
Definition TextBlock.cs:358
Represents a base class for hosting a render surface, providing functionality for managing rendering ...
Represents a rendered view of a scene, combining a camera position with a viewport configuration to c...
Definition View.cs:14
override void OnPointerLeave(WidgetPointerEventArgs args)
Called when a pointer leaves the widget bounds.
CheckBoxWidget SetColors(Color normal, Color hover, Color mark)
Sets the normal, hover, and checked-mark colors.
CheckBoxWidget SetCheckBoxZOrder(int zOrder)
Sets the base Z-order used by the checkbox visuals.
CheckBoxWidget Toggle()
Toggles the checkbox state.
DirectRectangle Box
Gets the outer checkbox indicator.
CheckBoxWidget SetText(string text)
Changes the checkbox label text.
CheckBoxWidget(RenderSurfaceHostBase renderSurfaceHost, View view, Rectangle bounds, string text, bool isChecked=false, string? nickname=null)
Creates a view-level checkbox.
override void ProcessShown()
Performs processing when the widget is shown before notification callbacks are invoked.
override void OnPointerEnter(WidgetPointerEventArgs args)
Called when a pointer enters the widget bounds.
CheckBoxWidget SetChecked(bool isChecked)
Sets the checkbox state.
bool IsChecked
Gets or sets whether the checkbox is checked.
CheckBoxWidget(RenderSurfaceHostBase renderSurfaceHost, SceneLayer sceneLayer, Rectangle bounds, string text, bool isChecked=false, string? nickname=null)
Creates a scene-layer checkbox.
CheckBoxWidget SetTextColor(SKColor color)
Sets the label text color.
override void OnKeyboardInput(WidgetKeyboardEventArgs args)
Called when keyboard input is routed to the widget.
DirectRectangle Mark
Gets the filled mark displayed while the checkbox is checked.
Action< bool >? CheckedChanged
Occurs when IsChecked changes.
TextBlock Label
Gets the text label displayed beside the checkbox.
Rectangle Bounds
Gets the checkbox bounds in its native coordinate space.
override void OnPointerClick(WidgetPointerEventArgs args)
Called when a pointer click is dispatched to the widget.
bool CanReceiveFocus
Gets or sets a value indicating whether the widget can receive keyboard focus.
WidgetBase(RenderSurfaceHostBase renderSurfaceHost, DirectDrawingMode mode, PointF anchor=default, string? nickname=null)
Initializes a new instance of the WidgetBase class.
Definition WidgetBase.cs:95
bool IsFocused
Gets a value indicating whether the widget currently has keyboard focus.
bool IsKeyboardInputEnabled
Gets or sets a value indicating whether the widget can receive keyboard input.
Provides data for widget keyboard input events routed by WidgetInputRouter.
int Key
Gets the integer key identifier.
KeyAction KeyAction
Gets the action associated with this key event.
Event arguments for pointer-based widget callbacks.
bool IsPrimaryButton
Gets whether the pointer event represents a primary-button interaction.
@ 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.
@ View
Performs direct drawing at the view level using screen-space coordinates.
KeyAction
Represents the type of action performed on a keyboard key, indicating whether the key was pressed,...
Definition KeyAction.cs:10