2025-12-19 09:30:16 +00:00
|
|
|
// Licensed to the .NET Foundation under one or more agreements.
|
|
|
|
|
// The .NET Foundation licenses this file to you under the MIT license.
|
|
|
|
|
|
2026-01-01 13:51:12 -05:00
|
|
|
using System;
|
|
|
|
|
using System.Windows.Input;
|
|
|
|
|
using Microsoft.Maui.Controls;
|
2026-01-16 04:14:34 +00:00
|
|
|
using Microsoft.Maui.Graphics;
|
2025-12-19 09:30:16 +00:00
|
|
|
using Microsoft.Maui.Platform.Linux.Rendering;
|
2026-01-01 13:51:12 -05:00
|
|
|
using SkiaSharp;
|
2025-12-19 09:30:16 +00:00
|
|
|
|
|
|
|
|
namespace Microsoft.Maui.Platform;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2026-01-16 04:14:34 +00:00
|
|
|
/// Skia-rendered button control matching the .NET MAUI Button API.
|
2025-12-19 09:30:16 +00:00
|
|
|
/// </summary>
|
2026-01-16 04:14:34 +00:00
|
|
|
public class SkiaButton : SkiaView, IButtonController
|
2025-12-19 09:30:16 +00:00
|
|
|
{
|
2025-12-21 13:26:56 -05:00
|
|
|
#region BindableProperties
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Bindable property for Text.
|
|
|
|
|
/// </summary>
|
2026-01-01 13:51:12 -05:00
|
|
|
public static readonly BindableProperty TextProperty = BindableProperty.Create(
|
|
|
|
|
nameof(Text),
|
|
|
|
|
typeof(string),
|
|
|
|
|
typeof(SkiaButton),
|
2026-01-16 04:14:34 +00:00
|
|
|
string.Empty,
|
2026-01-01 13:51:12 -05:00
|
|
|
propertyChanged: (b, o, n) => ((SkiaButton)b).OnTextChanged());
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Bindable property for TextColor.
|
2026-01-17 01:43:42 +00:00
|
|
|
/// Default is null to match MAUI Button.TextColor (falls back to platform default).
|
2026-01-16 04:14:34 +00:00
|
|
|
/// </summary>
|
2026-01-01 13:51:12 -05:00
|
|
|
public static readonly BindableProperty TextColorProperty = BindableProperty.Create(
|
|
|
|
|
nameof(TextColor),
|
2026-01-16 04:14:34 +00:00
|
|
|
typeof(Color),
|
2026-01-01 13:51:12 -05:00
|
|
|
typeof(SkiaButton),
|
2026-01-17 01:43:42 +00:00
|
|
|
null,
|
2026-01-01 13:51:12 -05:00
|
|
|
propertyChanged: (b, o, n) => ((SkiaButton)b).Invalidate());
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Bindable property for CharacterSpacing.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static readonly BindableProperty CharacterSpacingProperty = BindableProperty.Create(
|
|
|
|
|
nameof(CharacterSpacing),
|
|
|
|
|
typeof(double),
|
2026-01-01 13:51:12 -05:00
|
|
|
typeof(SkiaButton),
|
2026-01-16 04:14:34 +00:00
|
|
|
0.0,
|
|
|
|
|
propertyChanged: (b, o, n) => ((SkiaButton)b).InvalidateMeasure());
|
2026-01-01 13:51:12 -05:00
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Bindable property for FontFamily.
|
|
|
|
|
/// </summary>
|
2026-01-01 13:51:12 -05:00
|
|
|
public static readonly BindableProperty FontFamilyProperty = BindableProperty.Create(
|
|
|
|
|
nameof(FontFamily),
|
|
|
|
|
typeof(string),
|
|
|
|
|
typeof(SkiaButton),
|
2026-01-16 04:14:34 +00:00
|
|
|
string.Empty,
|
2026-01-01 13:51:12 -05:00
|
|
|
propertyChanged: (b, o, n) => ((SkiaButton)b).OnFontChanged());
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Bindable property for FontSize.
|
|
|
|
|
/// </summary>
|
2026-01-01 13:51:12 -05:00
|
|
|
public static readonly BindableProperty FontSizeProperty = BindableProperty.Create(
|
|
|
|
|
nameof(FontSize),
|
2026-01-16 04:14:34 +00:00
|
|
|
typeof(double),
|
2026-01-01 13:51:12 -05:00
|
|
|
typeof(SkiaButton),
|
2026-01-16 04:14:34 +00:00
|
|
|
14.0,
|
2026-01-01 13:51:12 -05:00
|
|
|
propertyChanged: (b, o, n) => ((SkiaButton)b).OnFontChanged());
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Bindable property for FontAttributes.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static readonly BindableProperty FontAttributesProperty = BindableProperty.Create(
|
|
|
|
|
nameof(FontAttributes),
|
|
|
|
|
typeof(FontAttributes),
|
2026-01-01 13:51:12 -05:00
|
|
|
typeof(SkiaButton),
|
2026-01-16 04:14:34 +00:00
|
|
|
FontAttributes.None,
|
2026-01-01 13:51:12 -05:00
|
|
|
propertyChanged: (b, o, n) => ((SkiaButton)b).OnFontChanged());
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Bindable property for FontAutoScalingEnabled.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static readonly BindableProperty FontAutoScalingEnabledProperty = BindableProperty.Create(
|
|
|
|
|
nameof(FontAutoScalingEnabled),
|
2026-01-01 13:51:12 -05:00
|
|
|
typeof(bool),
|
|
|
|
|
typeof(SkiaButton),
|
2026-01-16 04:14:34 +00:00
|
|
|
true,
|
2026-01-01 13:51:12 -05:00
|
|
|
propertyChanged: (b, o, n) => ((SkiaButton)b).OnFontChanged());
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Bindable property for TextTransform.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static readonly BindableProperty TextTransformProperty = BindableProperty.Create(
|
|
|
|
|
nameof(TextTransform),
|
|
|
|
|
typeof(TextTransform),
|
2026-01-01 13:51:12 -05:00
|
|
|
typeof(SkiaButton),
|
2026-01-16 04:14:34 +00:00
|
|
|
TextTransform.Default,
|
2026-01-01 13:51:12 -05:00
|
|
|
propertyChanged: (b, o, n) => ((SkiaButton)b).Invalidate());
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Bindable property for BorderColor.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static readonly BindableProperty BorderColorProperty = BindableProperty.Create(
|
|
|
|
|
nameof(BorderColor),
|
|
|
|
|
typeof(Color),
|
2026-01-01 13:51:12 -05:00
|
|
|
typeof(SkiaButton),
|
2026-01-16 04:14:34 +00:00
|
|
|
null,
|
2026-01-01 13:51:12 -05:00
|
|
|
propertyChanged: (b, o, n) => ((SkiaButton)b).Invalidate());
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Bindable property for BorderWidth.
|
2026-01-17 01:43:42 +00:00
|
|
|
/// Default is -1 to match MAUI Button.BorderWidth (unset/platform default).
|
2026-01-16 04:14:34 +00:00
|
|
|
/// </summary>
|
2026-01-01 13:51:12 -05:00
|
|
|
public static readonly BindableProperty BorderWidthProperty = BindableProperty.Create(
|
|
|
|
|
nameof(BorderWidth),
|
2026-01-16 04:14:34 +00:00
|
|
|
typeof(double),
|
|
|
|
|
typeof(SkiaButton),
|
2026-01-17 01:43:42 +00:00
|
|
|
-1.0,
|
2026-01-16 04:14:34 +00:00
|
|
|
propertyChanged: (b, o, n) => ((SkiaButton)b).Invalidate());
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Bindable property for CornerRadius.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static readonly BindableProperty CornerRadiusProperty = BindableProperty.Create(
|
|
|
|
|
nameof(CornerRadius),
|
|
|
|
|
typeof(int),
|
2026-01-01 13:51:12 -05:00
|
|
|
typeof(SkiaButton),
|
2026-01-16 04:14:34 +00:00
|
|
|
-1,
|
2026-01-01 13:51:12 -05:00
|
|
|
propertyChanged: (b, o, n) => ((SkiaButton)b).Invalidate());
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Bindable property for Padding.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static new readonly BindableProperty PaddingProperty = BindableProperty.Create(
|
2026-01-01 13:51:12 -05:00
|
|
|
nameof(Padding),
|
2026-01-16 04:14:34 +00:00
|
|
|
typeof(Thickness),
|
2026-01-01 13:51:12 -05:00
|
|
|
typeof(SkiaButton),
|
2026-01-16 04:14:34 +00:00
|
|
|
new Thickness(14, 10),
|
2026-01-01 13:51:12 -05:00
|
|
|
propertyChanged: (b, o, n) => ((SkiaButton)b).InvalidateMeasure());
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Bindable property for Command.
|
|
|
|
|
/// </summary>
|
2026-01-01 13:51:12 -05:00
|
|
|
public static readonly BindableProperty CommandProperty = BindableProperty.Create(
|
|
|
|
|
nameof(Command),
|
|
|
|
|
typeof(ICommand),
|
|
|
|
|
typeof(SkiaButton),
|
|
|
|
|
null,
|
|
|
|
|
propertyChanged: (b, o, n) => ((SkiaButton)b).OnCommandChanged((ICommand?)o, (ICommand?)n));
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Bindable property for CommandParameter.
|
|
|
|
|
/// </summary>
|
2026-01-01 13:51:12 -05:00
|
|
|
public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create(
|
|
|
|
|
nameof(CommandParameter),
|
|
|
|
|
typeof(object),
|
|
|
|
|
typeof(SkiaButton),
|
2026-01-16 04:14:34 +00:00
|
|
|
null);
|
2026-01-01 13:51:12 -05:00
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Bindable property for ImageSource.
|
|
|
|
|
/// </summary>
|
2026-01-01 13:51:12 -05:00
|
|
|
public static readonly BindableProperty ImageSourceProperty = BindableProperty.Create(
|
|
|
|
|
nameof(ImageSource),
|
2026-01-16 04:14:34 +00:00
|
|
|
typeof(ImageSource),
|
2026-01-01 13:51:12 -05:00
|
|
|
typeof(SkiaButton),
|
|
|
|
|
null,
|
2026-01-16 04:14:34 +00:00
|
|
|
propertyChanged: (b, o, n) => ((SkiaButton)b).OnImageSourceChanged());
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Bindable property for ContentLayout.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static readonly BindableProperty ContentLayoutProperty = BindableProperty.Create(
|
|
|
|
|
nameof(ContentLayout),
|
|
|
|
|
typeof(ButtonContentLayout),
|
2026-01-01 13:51:12 -05:00
|
|
|
typeof(SkiaButton),
|
2026-01-16 04:14:34 +00:00
|
|
|
new ButtonContentLayout(ButtonContentLayout.ImagePosition.Left, 10),
|
2026-01-01 13:51:12 -05:00
|
|
|
propertyChanged: (b, o, n) => ((SkiaButton)b).InvalidateMeasure());
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Bindable property for LineBreakMode.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static readonly BindableProperty LineBreakModeProperty = BindableProperty.Create(
|
|
|
|
|
nameof(LineBreakMode),
|
|
|
|
|
typeof(LineBreakMode),
|
2026-01-01 13:51:12 -05:00
|
|
|
typeof(SkiaButton),
|
2026-01-16 04:14:34 +00:00
|
|
|
LineBreakMode.NoWrap,
|
|
|
|
|
propertyChanged: (b, o, n) => ((SkiaButton)b).Invalidate());
|
2026-01-01 13:51:12 -05:00
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Fields
|
|
|
|
|
|
|
|
|
|
private bool _focusFromKeyboard;
|
2026-01-16 04:14:34 +00:00
|
|
|
private SKBitmap? _loadedImage;
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
|
2025-12-21 13:26:56 -05:00
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Properties
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Gets or sets the text displayed on the button.
|
|
|
|
|
/// </summary>
|
2025-12-21 13:26:56 -05:00
|
|
|
public string Text
|
|
|
|
|
{
|
|
|
|
|
get => (string)GetValue(TextProperty);
|
|
|
|
|
set => SetValue(TextProperty, value);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Gets or sets the color of the text.
|
2026-01-17 01:43:42 +00:00
|
|
|
/// Null means use platform default (white on buttons for Linux).
|
2026-01-16 04:14:34 +00:00
|
|
|
/// </summary>
|
2026-01-17 01:43:42 +00:00
|
|
|
public Color? TextColor
|
2025-12-21 13:26:56 -05:00
|
|
|
{
|
2026-01-17 01:43:42 +00:00
|
|
|
get => (Color?)GetValue(TextColorProperty);
|
2025-12-21 13:26:56 -05:00
|
|
|
set => SetValue(TextColorProperty, value);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Gets or sets the spacing between characters in the text.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public double CharacterSpacing
|
2025-12-21 13:26:56 -05:00
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
get => (double)GetValue(CharacterSpacingProperty);
|
|
|
|
|
set => SetValue(CharacterSpacingProperty, value);
|
2025-12-21 13:26:56 -05:00
|
|
|
}
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Gets or sets the font family.
|
|
|
|
|
/// </summary>
|
2025-12-21 13:26:56 -05:00
|
|
|
public string FontFamily
|
|
|
|
|
{
|
|
|
|
|
get => (string)GetValue(FontFamilyProperty);
|
|
|
|
|
set => SetValue(FontFamilyProperty, value);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Gets or sets the font size.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public double FontSize
|
2025-12-21 13:26:56 -05:00
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
get => (double)GetValue(FontSizeProperty);
|
2025-12-21 13:26:56 -05:00
|
|
|
set => SetValue(FontSizeProperty, value);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Gets or sets the font attributes (bold, italic).
|
|
|
|
|
/// </summary>
|
|
|
|
|
public FontAttributes FontAttributes
|
2025-12-21 13:26:56 -05:00
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
get => (FontAttributes)GetValue(FontAttributesProperty);
|
|
|
|
|
set => SetValue(FontAttributesProperty, value);
|
2025-12-21 13:26:56 -05:00
|
|
|
}
|
2025-12-19 09:30:16 +00:00
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Gets or sets whether font auto-scaling is enabled.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool FontAutoScalingEnabled
|
2025-12-21 13:26:56 -05:00
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
get => (bool)GetValue(FontAutoScalingEnabledProperty);
|
|
|
|
|
set => SetValue(FontAutoScalingEnabledProperty, value);
|
2025-12-21 13:26:56 -05:00
|
|
|
}
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Gets or sets the text transform.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public TextTransform TextTransform
|
2025-12-21 13:26:56 -05:00
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
get => (TextTransform)GetValue(TextTransformProperty);
|
|
|
|
|
set => SetValue(TextTransformProperty, value);
|
2025-12-21 13:26:56 -05:00
|
|
|
}
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Gets or sets the border color.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public Color BorderColor
|
2025-12-21 13:26:56 -05:00
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
get => (Color)GetValue(BorderColorProperty);
|
|
|
|
|
set => SetValue(BorderColorProperty, value);
|
2025-12-21 13:26:56 -05:00
|
|
|
}
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Gets or sets the border width.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public double BorderWidth
|
2025-12-21 13:26:56 -05:00
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
get => (double)GetValue(BorderWidthProperty);
|
2025-12-21 13:26:56 -05:00
|
|
|
set => SetValue(BorderWidthProperty, value);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Gets or sets the corner radius.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int CornerRadius
|
2025-12-21 13:26:56 -05:00
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
get => (int)GetValue(CornerRadiusProperty);
|
|
|
|
|
set => SetValue(CornerRadiusProperty, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets or sets the padding.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public new Thickness Padding
|
|
|
|
|
{
|
|
|
|
|
get => (Thickness)GetValue(PaddingProperty);
|
2025-12-21 13:26:56 -05:00
|
|
|
set => SetValue(PaddingProperty, value);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Gets or sets the command to execute when clicked.
|
|
|
|
|
/// </summary>
|
2026-01-01 13:51:12 -05:00
|
|
|
public ICommand? Command
|
2025-12-21 13:26:56 -05:00
|
|
|
{
|
2026-01-01 13:51:12 -05:00
|
|
|
get => (ICommand?)GetValue(CommandProperty);
|
2025-12-21 13:26:56 -05:00
|
|
|
set => SetValue(CommandProperty, value);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Gets or sets the parameter passed to the command.
|
|
|
|
|
/// </summary>
|
2025-12-21 13:26:56 -05:00
|
|
|
public object? CommandParameter
|
|
|
|
|
{
|
|
|
|
|
get => GetValue(CommandParameterProperty);
|
|
|
|
|
set => SetValue(CommandParameterProperty, value);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Gets or sets the image source.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public ImageSource? ImageSource
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
get => (ImageSource?)GetValue(ImageSourceProperty);
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
set => SetValue(ImageSourceProperty, value);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Gets or sets the content layout (image position and spacing).
|
|
|
|
|
/// </summary>
|
|
|
|
|
public ButtonContentLayout ContentLayout
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
get => (ButtonContentLayout)GetValue(ContentLayoutProperty);
|
|
|
|
|
set => SetValue(ContentLayoutProperty, value);
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
}
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Gets or sets the line break mode.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public LineBreakMode LineBreakMode
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
get => (LineBreakMode)GetValue(LineBreakModeProperty);
|
|
|
|
|
set => SetValue(LineBreakModeProperty, value);
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
}
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Gets whether the button is currently pressed.
|
|
|
|
|
/// </summary>
|
2025-12-19 09:30:16 +00:00
|
|
|
public bool IsPressed { get; private set; }
|
2025-12-21 13:26:56 -05:00
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Gets whether the pointer is over the button.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool IsPointerOver { get; private set; }
|
2025-12-21 13:26:56 -05:00
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2026-01-01 13:51:12 -05:00
|
|
|
#region Events
|
2025-12-19 09:30:16 +00:00
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Occurs when the button is clicked.
|
|
|
|
|
/// </summary>
|
2025-12-19 09:30:16 +00:00
|
|
|
public event EventHandler? Clicked;
|
2025-12-21 13:26:56 -05:00
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Occurs when the button is pressed.
|
|
|
|
|
/// </summary>
|
2025-12-19 09:30:16 +00:00
|
|
|
public event EventHandler? Pressed;
|
2025-12-21 13:26:56 -05:00
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Occurs when the button is released.
|
|
|
|
|
/// </summary>
|
2025-12-19 09:30:16 +00:00
|
|
|
public event EventHandler? Released;
|
|
|
|
|
|
2026-01-01 13:51:12 -05:00
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Constructor
|
|
|
|
|
|
2025-12-19 09:30:16 +00:00
|
|
|
public SkiaButton()
|
|
|
|
|
{
|
|
|
|
|
IsFocusable = true;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-01 13:51:12 -05:00
|
|
|
#endregion
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
#region IButtonController
|
|
|
|
|
|
|
|
|
|
void IButtonController.SendClicked() => OnClicked();
|
|
|
|
|
void IButtonController.SendPressed() => OnPressed();
|
|
|
|
|
void IButtonController.SendReleased() => OnReleased();
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2026-01-01 13:51:12 -05:00
|
|
|
#region Private Methods
|
|
|
|
|
|
2025-12-21 13:26:56 -05:00
|
|
|
private void OnTextChanged()
|
|
|
|
|
{
|
|
|
|
|
InvalidateMeasure();
|
|
|
|
|
Invalidate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnFontChanged()
|
|
|
|
|
{
|
|
|
|
|
InvalidateMeasure();
|
|
|
|
|
Invalidate();
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
private void OnImageSourceChanged()
|
|
|
|
|
{
|
|
|
|
|
// Load the image asynchronously
|
|
|
|
|
LoadImageAsync();
|
|
|
|
|
InvalidateMeasure();
|
|
|
|
|
Invalidate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async void LoadImageAsync()
|
|
|
|
|
{
|
|
|
|
|
_loadedImage = null;
|
|
|
|
|
if (ImageSource == null) return;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// Handle FileImageSource
|
|
|
|
|
if (ImageSource is FileImageSource fileSource)
|
|
|
|
|
{
|
|
|
|
|
var path = fileSource.File;
|
|
|
|
|
if (System.IO.File.Exists(path))
|
|
|
|
|
{
|
|
|
|
|
_loadedImage = SKBitmap.Decode(path);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Handle StreamImageSource
|
|
|
|
|
else if (ImageSource is StreamImageSource streamSource)
|
|
|
|
|
{
|
|
|
|
|
var stream = await streamSource.Stream(System.Threading.CancellationToken.None);
|
|
|
|
|
if (stream != null)
|
|
|
|
|
{
|
|
|
|
|
_loadedImage = SKBitmap.Decode(stream);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Handle UriImageSource
|
|
|
|
|
else if (ImageSource is UriImageSource uriSource)
|
|
|
|
|
{
|
|
|
|
|
using var client = new System.Net.Http.HttpClient();
|
|
|
|
|
var data = await client.GetByteArrayAsync(uriSource.Uri);
|
|
|
|
|
_loadedImage = SKBitmap.Decode(data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Invalidate();
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
// Image loading failed - leave as null
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-01 13:51:12 -05:00
|
|
|
private void OnCommandChanged(ICommand? oldCommand, ICommand? newCommand)
|
2025-12-21 13:26:56 -05:00
|
|
|
{
|
|
|
|
|
if (oldCommand != null)
|
|
|
|
|
{
|
|
|
|
|
oldCommand.CanExecuteChanged -= OnCanExecuteChanged;
|
|
|
|
|
}
|
|
|
|
|
if (newCommand != null)
|
|
|
|
|
{
|
|
|
|
|
newCommand.CanExecuteChanged += OnCanExecuteChanged;
|
|
|
|
|
UpdateIsEnabled();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnCanExecuteChanged(object? sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
UpdateIsEnabled();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void UpdateIsEnabled()
|
|
|
|
|
{
|
|
|
|
|
if (Command != null)
|
|
|
|
|
{
|
|
|
|
|
IsEnabled = Command.CanExecute(CommandParameter);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
private void OnClicked()
|
|
|
|
|
{
|
|
|
|
|
Clicked?.Invoke(this, EventArgs.Empty);
|
|
|
|
|
if (Command?.CanExecute(CommandParameter) == true)
|
|
|
|
|
{
|
|
|
|
|
Command.Execute(CommandParameter);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnPressed()
|
|
|
|
|
{
|
|
|
|
|
Pressed?.Invoke(this, EventArgs.Empty);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnReleased()
|
|
|
|
|
{
|
|
|
|
|
Released?.Invoke(this, EventArgs.Empty);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string ApplyTextTransform(string? text)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrEmpty(text)) return text ?? string.Empty;
|
|
|
|
|
return TextTransform switch
|
|
|
|
|
{
|
|
|
|
|
TextTransform.Uppercase => text.ToUpperInvariant(),
|
|
|
|
|
TextTransform.Lowercase => text.ToLowerInvariant(),
|
|
|
|
|
_ => text
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private SKColor ToSKColor(Color? color)
|
|
|
|
|
{
|
|
|
|
|
if (color == null) return SKColors.Transparent;
|
2026-01-17 03:36:37 +00:00
|
|
|
return color.ToSKColor();
|
2026-01-16 04:14:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private float GetEffectiveCornerRadius()
|
|
|
|
|
{
|
|
|
|
|
// MAUI uses -1 to mean "use default" which is typically 5
|
|
|
|
|
return CornerRadius < 0 ? 5f : CornerRadius;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-01 13:51:12 -05:00
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Drawing
|
|
|
|
|
|
2026-01-24 01:53:26 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Override to prevent base class from drawing rectangular background.
|
|
|
|
|
/// Button draws its own rounded background in OnDraw.
|
|
|
|
|
/// </summary>
|
|
|
|
|
protected override void DrawBackground(SKCanvas canvas, SKRect bounds)
|
|
|
|
|
{
|
|
|
|
|
// Don't draw anything - OnDraw handles the rounded background
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-19 09:30:16 +00:00
|
|
|
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
|
|
|
|
|
{
|
2026-01-17 03:10:29 +00:00
|
|
|
// BackgroundColor is inherited from SkiaView as MAUI Color - convert to SKColor for rendering
|
|
|
|
|
var bgColor = GetEffectiveBackgroundColor();
|
2026-01-24 01:53:26 +00:00
|
|
|
|
|
|
|
|
// Check if BackgroundColor was explicitly set (even if set to transparent)
|
|
|
|
|
// This distinguishes "no background specified" from "explicitly transparent"
|
|
|
|
|
bool hasExplicitBackground = BackgroundColor != null;
|
|
|
|
|
|
|
|
|
|
// If no background color is set, use a default button background (like other MAUI platforms)
|
|
|
|
|
// This ensures buttons are visible even without explicit styling
|
|
|
|
|
if (!hasExplicitBackground)
|
|
|
|
|
{
|
2026-01-24 02:21:56 +00:00
|
|
|
bgColor = SkiaTheme.ButtonBackgroundSK; // Theme-aware default button background
|
2026-01-24 01:53:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool hasBackground = hasExplicitBackground ? bgColor.Alpha > 0 : true;
|
2025-12-19 09:30:16 +00:00
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
// Determine current state color
|
|
|
|
|
SKColor currentBgColor;
|
2025-12-21 13:26:56 -05:00
|
|
|
if (!IsEnabled)
|
2025-12-19 09:30:16 +00:00
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
currentBgColor = hasBackground ? bgColor.WithAlpha(128) : SKColors.Transparent;
|
2025-12-21 13:26:56 -05:00
|
|
|
}
|
|
|
|
|
else if (IsPressed)
|
|
|
|
|
{
|
2026-01-17 03:36:37 +00:00
|
|
|
currentBgColor = hasBackground ? DarkenColor(bgColor, 0.2f) : SkiaTheme.Shadow20SK;
|
2025-12-21 13:26:56 -05:00
|
|
|
}
|
2026-01-16 04:14:34 +00:00
|
|
|
else if (IsPointerOver)
|
2025-12-21 13:26:56 -05:00
|
|
|
{
|
2026-01-17 03:36:37 +00:00
|
|
|
currentBgColor = hasBackground ? LightenColor(bgColor, 0.1f) : SkiaTheme.Shadow10SK;
|
2025-12-21 13:26:56 -05:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
currentBgColor = bgColor;
|
2025-12-19 09:30:16 +00:00
|
|
|
}
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
float cornerRadius = GetEffectiveCornerRadius();
|
|
|
|
|
|
|
|
|
|
// Draw shadow for raised buttons
|
|
|
|
|
if (IsEnabled && !IsPressed && hasBackground)
|
2025-12-19 09:30:16 +00:00
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
DrawButtonShadow(canvas, bounds, cornerRadius);
|
2025-12-21 13:26:56 -05:00
|
|
|
}
|
2025-12-19 09:30:16 +00:00
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
var roundRect = new SKRoundRect(bounds, cornerRadius);
|
2025-12-21 13:26:56 -05:00
|
|
|
|
2026-01-24 01:53:26 +00:00
|
|
|
// Clip to rounded rectangle to prevent background bleeding in corners
|
|
|
|
|
canvas.Save();
|
|
|
|
|
canvas.ClipRoundRect(roundRect, antialias: true);
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
// Draw background
|
|
|
|
|
if (currentBgColor.Alpha > 0)
|
2025-12-21 13:26:56 -05:00
|
|
|
{
|
|
|
|
|
using var bgPaint = new SKPaint
|
|
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
Color = currentBgColor,
|
2025-12-21 13:26:56 -05:00
|
|
|
IsAntialias = true,
|
|
|
|
|
Style = SKPaintStyle.Fill
|
|
|
|
|
};
|
2026-01-01 13:51:12 -05:00
|
|
|
canvas.DrawRoundRect(roundRect, bgPaint);
|
2025-12-21 13:26:56 -05:00
|
|
|
}
|
2025-12-19 09:30:16 +00:00
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
// Draw border
|
|
|
|
|
if (BorderWidth > 0 && BorderColor != null)
|
2025-12-19 09:30:16 +00:00
|
|
|
{
|
|
|
|
|
using var borderPaint = new SKPaint
|
|
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
Color = ToSKColor(BorderColor),
|
2025-12-19 09:30:16 +00:00
|
|
|
IsAntialias = true,
|
|
|
|
|
Style = SKPaintStyle.Stroke,
|
2026-01-16 04:14:34 +00:00
|
|
|
StrokeWidth = (float)BorderWidth
|
2025-12-19 09:30:16 +00:00
|
|
|
};
|
2026-01-01 13:51:12 -05:00
|
|
|
canvas.DrawRoundRect(roundRect, borderPaint);
|
2025-12-19 09:30:16 +00:00
|
|
|
}
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
// Draw focus ring
|
2025-12-19 09:30:16 +00:00
|
|
|
if (IsFocused && _focusFromKeyboard)
|
|
|
|
|
{
|
|
|
|
|
using var focusPaint = new SKPaint
|
|
|
|
|
{
|
2026-01-17 03:36:37 +00:00
|
|
|
Color = SkiaTheme.PrimaryHalfSK,
|
2025-12-19 09:30:16 +00:00
|
|
|
IsAntialias = true,
|
|
|
|
|
Style = SKPaintStyle.Stroke,
|
2026-01-01 13:51:12 -05:00
|
|
|
StrokeWidth = 2f
|
2025-12-19 09:30:16 +00:00
|
|
|
};
|
2026-01-16 04:14:34 +00:00
|
|
|
var focusRect = new SKRoundRect(bounds, cornerRadius + 2f);
|
2026-01-01 13:51:12 -05:00
|
|
|
focusRect.Inflate(2f, 2f);
|
2025-12-19 09:30:16 +00:00
|
|
|
canvas.DrawRoundRect(focusRect, focusPaint);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
// Draw content (text and/or image)
|
2026-01-24 01:53:26 +00:00
|
|
|
DrawContent(canvas, bounds, hasExplicitBackground);
|
|
|
|
|
|
|
|
|
|
// Restore canvas state (undo clipping)
|
|
|
|
|
canvas.Restore();
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
}
|
|
|
|
|
|
2026-01-24 01:53:26 +00:00
|
|
|
private void DrawContent(SKCanvas canvas, SKRect bounds, bool hasExplicitBackground)
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
var padding = Padding;
|
2026-01-24 01:53:26 +00:00
|
|
|
// Handle NaN padding (default to 14, 10)
|
|
|
|
|
float padLeft = float.IsNaN((float)padding.Left) ? 14f : (float)padding.Left;
|
|
|
|
|
float padTop = float.IsNaN((float)padding.Top) ? 10f : (float)padding.Top;
|
|
|
|
|
float padRight = float.IsNaN((float)padding.Right) ? 14f : (float)padding.Right;
|
|
|
|
|
float padBottom = float.IsNaN((float)padding.Bottom) ? 10f : (float)padding.Bottom;
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
var contentBounds = new SKRect(
|
2026-01-24 01:53:26 +00:00
|
|
|
bounds.Left + padLeft,
|
|
|
|
|
bounds.Top + padTop,
|
|
|
|
|
bounds.Right - padRight,
|
|
|
|
|
bounds.Bottom - padBottom);
|
2026-01-16 04:14:34 +00:00
|
|
|
|
|
|
|
|
// Prepare font
|
|
|
|
|
bool isBold = FontAttributes.HasFlag(FontAttributes.Bold);
|
|
|
|
|
bool isItalic = FontAttributes.HasFlag(FontAttributes.Italic);
|
|
|
|
|
|
|
|
|
|
var fontStyle = new SKFontStyle(
|
|
|
|
|
isBold ? SKFontStyleWeight.Bold : SKFontStyleWeight.Normal,
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
SKFontStyleWidth.Normal,
|
2026-01-16 04:14:34 +00:00
|
|
|
isItalic ? SKFontStyleSlant.Italic : SKFontStyleSlant.Upright);
|
|
|
|
|
|
|
|
|
|
var fontFamily = string.IsNullOrEmpty(FontFamily) ? "Sans" : FontFamily;
|
|
|
|
|
float fontSize = FontSize > 0 ? (float)FontSize : 14f;
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
|
2026-01-01 13:51:12 -05:00
|
|
|
using var font = new SKFont(
|
2026-01-16 04:14:34 +00:00
|
|
|
SkiaRenderingEngine.Current?.ResourceCache.GetTypeface(fontFamily, fontStyle) ?? SKTypeface.Default,
|
|
|
|
|
fontSize);
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
|
2026-01-24 01:53:26 +00:00
|
|
|
// Prepare text color
|
|
|
|
|
// If TextColor is set, use it; otherwise use a sensible default based on background
|
|
|
|
|
SKColor textColor;
|
|
|
|
|
if (TextColor != null)
|
|
|
|
|
{
|
|
|
|
|
textColor = ToSKColor(TextColor);
|
|
|
|
|
}
|
|
|
|
|
else if (hasExplicitBackground)
|
|
|
|
|
{
|
|
|
|
|
// Explicit background but no text color - use white (common for colored buttons)
|
|
|
|
|
textColor = SkiaTheme.BackgroundWhiteSK;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2026-01-24 02:21:56 +00:00
|
|
|
// Default button - use theme-appropriate text color for contrast
|
|
|
|
|
textColor = SkiaTheme.CurrentTextSK;
|
2026-01-24 01:53:26 +00:00
|
|
|
}
|
|
|
|
|
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
if (!IsEnabled)
|
|
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
textColor = textColor.WithAlpha(128);
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
using var textPaint = new SKPaint(font)
|
2025-12-19 09:30:16 +00:00
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
Color = textColor,
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
IsAntialias = true
|
|
|
|
|
};
|
2025-12-19 09:30:16 +00:00
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
string displayText = ApplyTextTransform(Text);
|
|
|
|
|
bool hasText = !string.IsNullOrEmpty(displayText);
|
|
|
|
|
bool hasImage = _loadedImage != null;
|
|
|
|
|
|
|
|
|
|
// Measure text
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
var textBounds = new SKRect();
|
2026-01-16 04:14:34 +00:00
|
|
|
float textWidth = 0;
|
|
|
|
|
float textHeight = 0;
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
if (hasText)
|
|
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
textPaint.MeasureText(displayText, ref textBounds);
|
|
|
|
|
textWidth = textBounds.Width;
|
|
|
|
|
if (CharacterSpacing != 0 && displayText.Length > 1)
|
|
|
|
|
{
|
|
|
|
|
textWidth += (float)(CharacterSpacing * (displayText.Length - 1));
|
|
|
|
|
}
|
|
|
|
|
textHeight = textBounds.Height;
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
}
|
2025-12-21 13:26:56 -05:00
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
// Measure image
|
|
|
|
|
float imageWidth = 0;
|
|
|
|
|
float imageHeight = 0;
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
if (hasImage)
|
|
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
float maxImageSize = Math.Min(contentBounds.Height, 24f);
|
|
|
|
|
float scale = Math.Min(maxImageSize / _loadedImage!.Width, maxImageSize / _loadedImage.Height);
|
|
|
|
|
imageWidth = _loadedImage.Width * scale;
|
|
|
|
|
imageHeight = _loadedImage.Height * scale;
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
}
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
// Get layout settings
|
|
|
|
|
var layout = ContentLayout;
|
|
|
|
|
float spacing = (float)layout.Spacing;
|
|
|
|
|
bool isHorizontal = layout.Position == ButtonContentLayout.ImagePosition.Left ||
|
|
|
|
|
layout.Position == ButtonContentLayout.ImagePosition.Right;
|
2026-01-01 13:51:12 -05:00
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
// Calculate total content size
|
|
|
|
|
float totalWidth, totalHeight;
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
if (hasImage && hasText)
|
|
|
|
|
{
|
|
|
|
|
if (isHorizontal)
|
2025-12-21 13:26:56 -05:00
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
totalWidth = imageWidth + spacing + textWidth;
|
|
|
|
|
totalHeight = Math.Max(imageHeight, textHeight);
|
2025-12-21 13:26:56 -05:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
totalWidth = Math.Max(imageWidth, textWidth);
|
|
|
|
|
totalHeight = imageHeight + spacing + textHeight;
|
2025-12-21 13:26:56 -05:00
|
|
|
}
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
}
|
|
|
|
|
else if (hasImage)
|
|
|
|
|
{
|
|
|
|
|
totalWidth = imageWidth;
|
|
|
|
|
totalHeight = imageHeight;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
totalWidth = textWidth;
|
|
|
|
|
totalHeight = textHeight;
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
}
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
// Calculate starting position (centered)
|
|
|
|
|
float startX = contentBounds.MidX - totalWidth / 2;
|
|
|
|
|
float startY = contentBounds.MidY - totalHeight / 2;
|
2025-12-21 13:26:56 -05:00
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
// Draw based on layout position
|
|
|
|
|
if (hasImage && hasText)
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
float imageX, imageY, textX, textY;
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
switch (layout.Position)
|
2025-12-19 09:30:16 +00:00
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
case ButtonContentLayout.ImagePosition.Top:
|
|
|
|
|
imageX = contentBounds.MidX - imageWidth / 2;
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
imageY = startY;
|
2026-01-16 04:14:34 +00:00
|
|
|
textX = contentBounds.MidX - textWidth / 2;
|
|
|
|
|
textY = startY + imageHeight + spacing - textBounds.Top;
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
break;
|
2026-01-16 04:14:34 +00:00
|
|
|
|
|
|
|
|
case ButtonContentLayout.ImagePosition.Bottom:
|
|
|
|
|
textX = contentBounds.MidX - textWidth / 2;
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
textY = startY - textBounds.Top;
|
2026-01-16 04:14:34 +00:00
|
|
|
imageX = contentBounds.MidX - imageWidth / 2;
|
|
|
|
|
imageY = startY + textHeight + spacing;
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
break;
|
2026-01-16 04:14:34 +00:00
|
|
|
|
|
|
|
|
case ButtonContentLayout.ImagePosition.Right:
|
|
|
|
|
textX = startX;
|
|
|
|
|
textY = contentBounds.MidY - textBounds.MidY;
|
|
|
|
|
imageX = startX + textWidth + spacing;
|
|
|
|
|
imageY = contentBounds.MidY - imageHeight / 2;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default: // Left
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
imageX = startX;
|
2026-01-16 04:14:34 +00:00
|
|
|
imageY = contentBounds.MidY - imageHeight / 2;
|
|
|
|
|
textX = startX + imageWidth + spacing;
|
|
|
|
|
textY = contentBounds.MidY - textBounds.MidY;
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
break;
|
|
|
|
|
}
|
2025-12-19 09:30:16 +00:00
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
// Draw image
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
var imageRect = new SKRect(imageX, imageY, imageX + imageWidth, imageY + imageHeight);
|
|
|
|
|
using var imagePaint = new SKPaint { IsAntialias = true };
|
|
|
|
|
if (!IsEnabled)
|
|
|
|
|
{
|
2026-01-01 13:51:12 -05:00
|
|
|
imagePaint.ColorFilter = SKColorFilter.CreateBlendMode(
|
2026-01-17 03:36:37 +00:00
|
|
|
SkiaTheme.ScrollbarThumbSK, SKBlendMode.Modulate);
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
}
|
2026-01-16 04:14:34 +00:00
|
|
|
canvas.DrawBitmap(_loadedImage!, imageRect, imagePaint);
|
2026-01-01 13:51:12 -05:00
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
// Draw text
|
|
|
|
|
DrawTextWithSpacing(canvas, displayText, textX, textY, textPaint);
|
|
|
|
|
}
|
|
|
|
|
else if (hasImage)
|
|
|
|
|
{
|
|
|
|
|
float imageX = contentBounds.MidX - imageWidth / 2;
|
|
|
|
|
float imageY = contentBounds.MidY - imageHeight / 2;
|
|
|
|
|
var imageRect = new SKRect(imageX, imageY, imageX + imageWidth, imageY + imageHeight);
|
|
|
|
|
using var imagePaint = new SKPaint { IsAntialias = true };
|
|
|
|
|
if (!IsEnabled)
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
imagePaint.ColorFilter = SKColorFilter.CreateBlendMode(
|
2026-01-17 03:36:37 +00:00
|
|
|
SkiaTheme.ScrollbarThumbSK, SKBlendMode.Modulate);
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
}
|
2026-01-16 04:14:34 +00:00
|
|
|
canvas.DrawBitmap(_loadedImage!, imageRect, imagePaint);
|
|
|
|
|
}
|
|
|
|
|
else if (hasText)
|
|
|
|
|
{
|
|
|
|
|
float textX = contentBounds.MidX - textWidth / 2;
|
|
|
|
|
float textY = contentBounds.MidY - textBounds.MidY;
|
|
|
|
|
DrawTextWithSpacing(canvas, displayText, textX, textY, textPaint);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void DrawTextWithSpacing(SKCanvas canvas, string text, float x, float y, SKPaint paint)
|
|
|
|
|
{
|
|
|
|
|
if (CharacterSpacing == 0 || string.IsNullOrEmpty(text) || text.Length <= 1)
|
|
|
|
|
{
|
|
|
|
|
canvas.DrawText(text, x, y, paint);
|
2026-01-01 13:51:12 -05:00
|
|
|
return;
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
}
|
2026-01-01 13:51:12 -05:00
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
// Draw each character with spacing
|
|
|
|
|
float currentX = x;
|
|
|
|
|
foreach (char c in text)
|
Major production merge: GTK support, context menus, and dispatcher fixes
Core Infrastructure:
- Add Dispatching folder with LinuxDispatcher, LinuxDispatcherProvider, LinuxDispatcherTimer
- Add Native folder with P/Invoke wrappers (GTK, GLib, GDK, Cairo, WebKit)
- Add GTK host window system with GtkHostWindow and GtkSkiaSurfaceWidget
- Update LinuxApplication with GTK mode, theme handling, and icon support
- Fix duplicate LinuxDispatcher in LinuxMauiContext
Handlers:
- Add GtkWebViewManager and GtkWebViewPlatformView for GTK WebView
- Add FlexLayoutHandler and GestureManager
- Update multiple handlers with ToViewHandler fix and missing mappers
- Add MauiHandlerExtensions with ToViewHandler extension method
Views:
- Add SkiaContextMenu with hover, keyboard, and dark theme support
- Add LinuxDialogService with context menu management
- Add SkiaFlexLayout for flex container support
- Update SkiaShell with RefreshTheme, MauiShell, ContentRenderer
- Update SkiaWebView with SetMainWindow, ProcessGtkEvents
- Update SkiaImage with LoadFromBitmap method
Services:
- Add AppInfoService, ConnectivityService, DeviceDisplayService, DeviceInfoService
- Add GtkHostService, GtkContextMenuService, MauiIconGenerator
Window:
- Add CursorType enum and GtkHostWindow
- Update X11Window with SetIcon, SetCursor methods
Build: SUCCESS (0 errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 11:19:58 -05:00
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
string charStr = c.ToString();
|
|
|
|
|
canvas.DrawText(charStr, currentX, y, paint);
|
|
|
|
|
currentX += paint.MeasureText(charStr) + (float)CharacterSpacing;
|
2025-12-19 09:30:16 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
private void DrawButtonShadow(SKCanvas canvas, SKRect bounds, float cornerRadius)
|
2025-12-19 09:30:16 +00:00
|
|
|
{
|
|
|
|
|
using var shadowPaint = new SKPaint
|
|
|
|
|
{
|
2026-01-17 03:36:37 +00:00
|
|
|
Color = SkiaTheme.Shadow20SK,
|
2025-12-19 09:30:16 +00:00
|
|
|
IsAntialias = true,
|
2026-01-01 13:51:12 -05:00
|
|
|
MaskFilter = SKMaskFilter.CreateBlur(SKBlurStyle.Normal, 4f)
|
2025-12-19 09:30:16 +00:00
|
|
|
};
|
|
|
|
|
|
2026-01-01 13:51:12 -05:00
|
|
|
var shadowRect = new SKRoundRect(
|
|
|
|
|
new SKRect(bounds.Left + 2f, bounds.Top + 4f, bounds.Right + 2f, bounds.Bottom + 4f),
|
2026-01-16 04:14:34 +00:00
|
|
|
cornerRadius);
|
2026-01-01 13:51:12 -05:00
|
|
|
canvas.DrawRoundRect(shadowRect, shadowPaint);
|
2025-12-19 09:30:16 +00:00
|
|
|
}
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
private SKColor DarkenColor(SKColor color, float amount)
|
|
|
|
|
{
|
|
|
|
|
return new SKColor(
|
|
|
|
|
(byte)Math.Max(0, color.Red * (1 - amount)),
|
|
|
|
|
(byte)Math.Max(0, color.Green * (1 - amount)),
|
|
|
|
|
(byte)Math.Max(0, color.Blue * (1 - amount)),
|
|
|
|
|
color.Alpha);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private SKColor LightenColor(SKColor color, float amount)
|
|
|
|
|
{
|
|
|
|
|
return new SKColor(
|
|
|
|
|
(byte)Math.Min(255, color.Red + (255 - color.Red) * amount),
|
|
|
|
|
(byte)Math.Min(255, color.Green + (255 - color.Green) * amount),
|
|
|
|
|
(byte)Math.Min(255, color.Blue + (255 - color.Blue) * amount),
|
|
|
|
|
color.Alpha);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-01 13:51:12 -05:00
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Pointer Events
|
|
|
|
|
|
2025-12-19 09:30:16 +00:00
|
|
|
public override void OnPointerEntered(PointerEventArgs e)
|
|
|
|
|
{
|
2026-01-01 13:51:12 -05:00
|
|
|
if (IsEnabled)
|
|
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
IsPointerOver = true;
|
2026-01-01 13:51:12 -05:00
|
|
|
SkiaVisualStateManager.GoToState(this, "PointerOver");
|
|
|
|
|
Invalidate();
|
|
|
|
|
}
|
2025-12-19 09:30:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void OnPointerExited(PointerEventArgs e)
|
|
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
IsPointerOver = false;
|
2025-12-19 09:30:16 +00:00
|
|
|
if (IsPressed)
|
|
|
|
|
{
|
|
|
|
|
IsPressed = false;
|
|
|
|
|
}
|
2026-01-01 13:51:12 -05:00
|
|
|
SkiaVisualStateManager.GoToState(this, IsEnabled ? "Normal" : "Disabled");
|
2025-12-19 09:30:16 +00:00
|
|
|
Invalidate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void OnPointerPressed(PointerEventArgs e)
|
|
|
|
|
{
|
2026-01-01 13:51:12 -05:00
|
|
|
if (IsEnabled)
|
|
|
|
|
{
|
|
|
|
|
IsPressed = true;
|
|
|
|
|
_focusFromKeyboard = false;
|
|
|
|
|
SkiaVisualStateManager.GoToState(this, "Pressed");
|
|
|
|
|
Invalidate();
|
2026-01-16 04:14:34 +00:00
|
|
|
OnPressed();
|
2026-01-01 13:51:12 -05:00
|
|
|
}
|
2025-12-19 09:30:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void OnPointerReleased(PointerEventArgs e)
|
|
|
|
|
{
|
2026-01-01 13:51:12 -05:00
|
|
|
if (IsEnabled)
|
2025-12-19 09:30:16 +00:00
|
|
|
{
|
2026-01-01 13:51:12 -05:00
|
|
|
bool wasPressed = IsPressed;
|
|
|
|
|
IsPressed = false;
|
2026-01-16 04:14:34 +00:00
|
|
|
SkiaVisualStateManager.GoToState(this, IsPointerOver ? "PointerOver" : "Normal");
|
2026-01-01 13:51:12 -05:00
|
|
|
Invalidate();
|
2026-01-16 04:14:34 +00:00
|
|
|
OnReleased();
|
2026-01-01 13:51:12 -05:00
|
|
|
if (wasPressed)
|
|
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
OnClicked();
|
2026-01-01 13:51:12 -05:00
|
|
|
}
|
2025-12-19 09:30:16 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-01 13:51:12 -05:00
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Keyboard Events
|
|
|
|
|
|
2025-12-19 09:30:16 +00:00
|
|
|
public override void OnKeyDown(KeyEventArgs e)
|
|
|
|
|
{
|
2026-01-01 13:51:12 -05:00
|
|
|
if (IsEnabled && (e.Key == Key.Enter || e.Key == Key.Space))
|
2025-12-19 09:30:16 +00:00
|
|
|
{
|
|
|
|
|
IsPressed = true;
|
2025-12-21 13:26:56 -05:00
|
|
|
_focusFromKeyboard = true;
|
2026-01-01 13:51:12 -05:00
|
|
|
SkiaVisualStateManager.GoToState(this, "Pressed");
|
2025-12-19 09:30:16 +00:00
|
|
|
Invalidate();
|
2026-01-16 04:14:34 +00:00
|
|
|
OnPressed();
|
2025-12-19 09:30:16 +00:00
|
|
|
e.Handled = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void OnKeyUp(KeyEventArgs e)
|
|
|
|
|
{
|
2026-01-01 13:51:12 -05:00
|
|
|
if (IsEnabled && (e.Key == Key.Enter || e.Key == Key.Space))
|
2025-12-19 09:30:16 +00:00
|
|
|
{
|
|
|
|
|
if (IsPressed)
|
|
|
|
|
{
|
|
|
|
|
IsPressed = false;
|
2026-01-01 13:51:12 -05:00
|
|
|
SkiaVisualStateManager.GoToState(this, "Normal");
|
2025-12-19 09:30:16 +00:00
|
|
|
Invalidate();
|
2026-01-16 04:14:34 +00:00
|
|
|
OnReleased();
|
|
|
|
|
OnClicked();
|
2025-12-19 09:30:16 +00:00
|
|
|
}
|
|
|
|
|
e.Handled = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-01 13:51:12 -05:00
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region State Changes
|
|
|
|
|
|
2025-12-21 13:26:56 -05:00
|
|
|
protected override void OnEnabledChanged()
|
|
|
|
|
{
|
|
|
|
|
base.OnEnabledChanged();
|
2026-01-01 13:51:12 -05:00
|
|
|
SkiaVisualStateManager.GoToState(this, IsEnabled ? "Normal" : "Disabled");
|
2025-12-21 13:26:56 -05:00
|
|
|
}
|
|
|
|
|
|
2026-01-01 13:51:12 -05:00
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Measurement
|
|
|
|
|
|
2026-01-17 05:22:37 +00:00
|
|
|
protected override Size MeasureOverride(Size availableSize)
|
2025-12-19 09:30:16 +00:00
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
var padding = Padding;
|
|
|
|
|
float paddingH = (float)(padding.Left + padding.Right);
|
|
|
|
|
float paddingV = (float)(padding.Top + padding.Bottom);
|
2026-01-24 01:53:26 +00:00
|
|
|
|
|
|
|
|
// Handle NaN padding (can happen with style resolution issues)
|
|
|
|
|
if (float.IsNaN(paddingH)) paddingH = 28f; // Default: 14 + 14
|
|
|
|
|
if (float.IsNaN(paddingV)) paddingV = 20f; // Default: 10 + 10
|
|
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
float fontSize = FontSize > 0 ? (float)FontSize : 14f;
|
2025-12-21 13:26:56 -05:00
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
// Prepare font for measurement
|
|
|
|
|
bool isBold = FontAttributes.HasFlag(FontAttributes.Bold);
|
|
|
|
|
bool isItalic = FontAttributes.HasFlag(FontAttributes.Italic);
|
2025-12-19 09:30:16 +00:00
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
var fontStyle = new SKFontStyle(
|
|
|
|
|
isBold ? SKFontStyleWeight.Bold : SKFontStyleWeight.Normal,
|
2026-01-01 13:51:12 -05:00
|
|
|
SKFontStyleWidth.Normal,
|
2026-01-16 04:14:34 +00:00
|
|
|
isItalic ? SKFontStyleSlant.Italic : SKFontStyleSlant.Upright);
|
|
|
|
|
|
|
|
|
|
var fontFamily = string.IsNullOrEmpty(FontFamily) ? "Sans" : FontFamily;
|
2025-12-19 09:30:16 +00:00
|
|
|
|
2026-01-01 13:51:12 -05:00
|
|
|
using var font = new SKFont(
|
2026-01-16 04:14:34 +00:00
|
|
|
SkiaRenderingEngine.Current?.ResourceCache.GetTypeface(fontFamily, fontStyle) ?? SKTypeface.Default,
|
|
|
|
|
fontSize);
|
2025-12-19 09:30:16 +00:00
|
|
|
|
2026-01-01 13:51:12 -05:00
|
|
|
using var paint = new SKPaint(font);
|
2025-12-19 09:30:16 +00:00
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
string displayText = ApplyTextTransform(Text);
|
|
|
|
|
bool hasText = !string.IsNullOrEmpty(displayText);
|
|
|
|
|
bool hasImage = _loadedImage != null;
|
|
|
|
|
|
|
|
|
|
float textWidth = 0, textHeight = 0;
|
|
|
|
|
if (hasText)
|
|
|
|
|
{
|
|
|
|
|
var textBounds = new SKRect();
|
|
|
|
|
paint.MeasureText(displayText, ref textBounds);
|
|
|
|
|
textWidth = textBounds.Width;
|
|
|
|
|
if (CharacterSpacing != 0 && displayText.Length > 1)
|
|
|
|
|
{
|
|
|
|
|
textWidth += (float)(CharacterSpacing * (displayText.Length - 1));
|
|
|
|
|
}
|
2026-01-24 01:53:26 +00:00
|
|
|
// Use font metrics for proper line height (ascent is negative)
|
|
|
|
|
var metrics = font.Metrics;
|
|
|
|
|
textHeight = metrics.Descent - metrics.Ascent;
|
2026-01-16 04:14:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float imageWidth = 0, imageHeight = 0;
|
|
|
|
|
if (hasImage)
|
|
|
|
|
{
|
|
|
|
|
float maxImageSize = 24f;
|
|
|
|
|
float scale = Math.Min(maxImageSize / _loadedImage!.Width, maxImageSize / _loadedImage.Height);
|
|
|
|
|
imageWidth = _loadedImage.Width * scale;
|
|
|
|
|
imageHeight = _loadedImage.Height * scale;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float width, height;
|
|
|
|
|
var layout = ContentLayout;
|
|
|
|
|
bool isHorizontal = layout.Position == ButtonContentLayout.ImagePosition.Left ||
|
|
|
|
|
layout.Position == ButtonContentLayout.ImagePosition.Right;
|
2025-12-21 13:26:56 -05:00
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
if (hasImage && hasText)
|
|
|
|
|
{
|
|
|
|
|
if (isHorizontal)
|
|
|
|
|
{
|
|
|
|
|
width = imageWidth + (float)layout.Spacing + textWidth;
|
|
|
|
|
height = Math.Max(imageHeight, textHeight);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
width = Math.Max(imageWidth, textWidth);
|
|
|
|
|
height = imageHeight + (float)layout.Spacing + textHeight;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (hasImage)
|
2026-01-01 13:51:12 -05:00
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
width = imageWidth;
|
|
|
|
|
height = imageHeight;
|
2026-01-01 13:51:12 -05:00
|
|
|
}
|
2026-01-16 04:14:34 +00:00
|
|
|
else if (hasText)
|
|
|
|
|
{
|
|
|
|
|
width = textWidth;
|
|
|
|
|
height = textHeight;
|
|
|
|
|
}
|
|
|
|
|
else
|
2026-01-01 13:51:12 -05:00
|
|
|
{
|
2026-01-16 04:14:34 +00:00
|
|
|
width = 40f;
|
|
|
|
|
height = fontSize;
|
2026-01-01 13:51:12 -05:00
|
|
|
}
|
2025-12-21 13:26:56 -05:00
|
|
|
|
2026-01-16 04:14:34 +00:00
|
|
|
width += paddingH;
|
|
|
|
|
height += paddingV;
|
|
|
|
|
|
|
|
|
|
// Respect explicit size requests
|
|
|
|
|
if (WidthRequest >= 0)
|
2026-01-01 13:51:12 -05:00
|
|
|
{
|
2025-12-21 13:26:56 -05:00
|
|
|
width = (float)WidthRequest;
|
2026-01-01 13:51:12 -05:00
|
|
|
}
|
2026-01-16 04:14:34 +00:00
|
|
|
if (HeightRequest >= 0)
|
2026-01-01 13:51:12 -05:00
|
|
|
{
|
2025-12-21 13:26:56 -05:00
|
|
|
height = (float)HeightRequest;
|
2026-01-01 13:51:12 -05:00
|
|
|
}
|
2025-12-21 13:26:56 -05:00
|
|
|
|
2026-01-24 01:53:26 +00:00
|
|
|
var result = new Size(Math.Max(width, 44f), Math.Max(height, 36f));
|
|
|
|
|
if (Text == "Round")
|
|
|
|
|
Console.WriteLine($"[SkiaButton.Measure] Text='Round' WReq={WidthRequest} HReq={HeightRequest} width={width:F1} height={height:F1} result={result.Width:F0}x{result.Height:F0}");
|
|
|
|
|
return result;
|
2025-12-19 09:30:16 +00:00
|
|
|
}
|
2026-01-01 13:51:12 -05:00
|
|
|
|
|
|
|
|
#endregion
|
2025-12-19 09:30:16 +00:00
|
|
|
}
|
2026-01-16 04:14:34 +00:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Specifies the position of the image and the spacing between image and text on a Button.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public class ButtonContentLayout
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Specifies the position of the image relative to the text.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public enum ImagePosition
|
|
|
|
|
{
|
|
|
|
|
Left,
|
|
|
|
|
Top,
|
|
|
|
|
Right,
|
|
|
|
|
Bottom
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the position of the image.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public ImagePosition Position { get; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the spacing between the image and text.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public double Spacing { get; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Creates a new ButtonContentLayout.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public ButtonContentLayout(ImagePosition position, double spacing)
|
|
|
|
|
{
|
|
|
|
|
Position = position;
|
|
|
|
|
Spacing = spacing;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Interface for button controller (matches MAUI).
|
|
|
|
|
/// </summary>
|
|
|
|
|
public interface IButtonController
|
|
|
|
|
{
|
|
|
|
|
void SendClicked();
|
|
|
|
|
void SendPressed();
|
|
|
|
|
void SendReleased();
|
|
|
|
|
}
|