Verify Views files against decompiled, extract embedded types
Fixed files: - SkiaImageButton.cs: Added SVG support with multi-path search - SkiaNavigationPage.cs: Added LinuxApplication.IsGtkMode check - SkiaRefreshView.cs: Added ICommand support (Command, CommandParameter) - SkiaTemplatedView.cs: Added missing using statements Extracted embedded types to separate files (matching decompiled pattern): - From SkiaMenuBar.cs: MenuBarItem, MenuItem, SkiaMenuFlyout, MenuItemClickedEventArgs - From SkiaNavigationPage.cs: NavigationEventArgs - From SkiaTabbedPage.cs: TabItem - From SkiaVisualStateManager.cs: SkiaVisualStateGroupList, SkiaVisualStateGroup, SkiaVisualState, SkiaVisualStateSetter - From SkiaSwipeView.cs: SwipeItem, SwipeStartedEventArgs, SwipeEndedEventArgs - From SkiaFlyoutPage.cs: FlyoutLayoutBehavior (already separate) - From SkiaIndicatorView.cs: IndicatorShape (already separate) - From SkiaBorder.cs: SkiaFrame - From SkiaCarouselView.cs: PositionChangedEventArgs - From SkiaCollectionView.cs: SkiaSelectionMode, ItemsLayoutOrientation - From SkiaContentPresenter.cs: LayoutAlignment Verified matching decompiled: - SkiaContextMenu.cs, SkiaFlexLayout.cs, SkiaGraphicsView.cs Build: 0 errors 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
48
Services/AccessibilityServiceFactory.cs
Normal file
48
Services/AccessibilityServiceFactory.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public static class AccessibilityServiceFactory
|
||||
{
|
||||
private static IAccessibilityService? _instance;
|
||||
private static readonly object _lock = new();
|
||||
|
||||
public static IAccessibilityService Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_instance ??= CreateService();
|
||||
}
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
private static IAccessibilityService CreateService()
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new AtSpi2AccessibilityService();
|
||||
service.Initialize();
|
||||
return service;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new NullAccessibilityService();
|
||||
}
|
||||
}
|
||||
|
||||
public static void Reset()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_instance?.Shutdown();
|
||||
_instance = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Services/AccessibleAction.cs
Normal file
11
Services/AccessibleAction.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class AccessibleAction
|
||||
{
|
||||
public string Name { get; set; } = "";
|
||||
public string Description { get; set; } = "";
|
||||
public string KeyBinding { get; set; } = "";
|
||||
}
|
||||
14
Services/AccessibleProperty.cs
Normal file
14
Services/AccessibleProperty.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum AccessibleProperty
|
||||
{
|
||||
Name,
|
||||
Description,
|
||||
Role,
|
||||
Value,
|
||||
Parent,
|
||||
Children
|
||||
}
|
||||
20
Services/AccessibleRect.cs
Normal file
20
Services/AccessibleRect.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public struct AccessibleRect
|
||||
{
|
||||
public int X { get; set; }
|
||||
public int Y { get; set; }
|
||||
public int Width { get; set; }
|
||||
public int Height { get; set; }
|
||||
|
||||
public AccessibleRect(int x, int y, int width, int height)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Width = width;
|
||||
Height = height;
|
||||
}
|
||||
}
|
||||
52
Services/AccessibleRole.cs
Normal file
52
Services/AccessibleRole.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum AccessibleRole
|
||||
{
|
||||
Unknown,
|
||||
Window,
|
||||
Application,
|
||||
Panel,
|
||||
Frame,
|
||||
Button,
|
||||
CheckBox,
|
||||
RadioButton,
|
||||
ComboBox,
|
||||
Entry,
|
||||
Label,
|
||||
List,
|
||||
ListItem,
|
||||
Menu,
|
||||
MenuBar,
|
||||
MenuItem,
|
||||
ScrollBar,
|
||||
Slider,
|
||||
SpinButton,
|
||||
StatusBar,
|
||||
Tab,
|
||||
TabPanel,
|
||||
Text,
|
||||
ToggleButton,
|
||||
ToolBar,
|
||||
ToolTip,
|
||||
Tree,
|
||||
TreeItem,
|
||||
Image,
|
||||
ProgressBar,
|
||||
Separator,
|
||||
Link,
|
||||
Table,
|
||||
TableCell,
|
||||
TableRow,
|
||||
TableColumnHeader,
|
||||
TableRowHeader,
|
||||
PageTab,
|
||||
PageTabList,
|
||||
Dialog,
|
||||
Alert,
|
||||
Filler,
|
||||
Icon,
|
||||
Canvas
|
||||
}
|
||||
52
Services/AccessibleState.cs
Normal file
52
Services/AccessibleState.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum AccessibleState
|
||||
{
|
||||
Invalid,
|
||||
Active,
|
||||
Armed,
|
||||
Busy,
|
||||
Checked,
|
||||
Collapsed,
|
||||
Defunct,
|
||||
Editable,
|
||||
Enabled,
|
||||
Expandable,
|
||||
Expanded,
|
||||
Focusable,
|
||||
Focused,
|
||||
HasToolTip,
|
||||
Horizontal,
|
||||
Iconified,
|
||||
Modal,
|
||||
MultiLine,
|
||||
Multiselectable,
|
||||
Opaque,
|
||||
Pressed,
|
||||
Resizable,
|
||||
Selectable,
|
||||
Selected,
|
||||
Sensitive,
|
||||
Showing,
|
||||
SingleLine,
|
||||
Stale,
|
||||
Transient,
|
||||
Vertical,
|
||||
Visible,
|
||||
ManagesDescendants,
|
||||
Indeterminate,
|
||||
Required,
|
||||
Truncated,
|
||||
Animated,
|
||||
InvalidEntry,
|
||||
SupportsAutocompletion,
|
||||
SelectableText,
|
||||
IsDefault,
|
||||
Visited,
|
||||
Checkable,
|
||||
HasPopup,
|
||||
ReadOnly
|
||||
}
|
||||
51
Services/AccessibleStates.cs
Normal file
51
Services/AccessibleStates.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
[Flags]
|
||||
public enum AccessibleStates : long
|
||||
{
|
||||
None = 0L,
|
||||
Active = 1L,
|
||||
Armed = 2L,
|
||||
Busy = 4L,
|
||||
Checked = 8L,
|
||||
Collapsed = 0x10L,
|
||||
Defunct = 0x20L,
|
||||
Editable = 0x40L,
|
||||
Enabled = 0x80L,
|
||||
Expandable = 0x100L,
|
||||
Expanded = 0x200L,
|
||||
Focusable = 0x400L,
|
||||
Focused = 0x800L,
|
||||
HasToolTip = 0x1000L,
|
||||
Horizontal = 0x2000L,
|
||||
Iconified = 0x4000L,
|
||||
Modal = 0x8000L,
|
||||
MultiLine = 0x10000L,
|
||||
MultiSelectable = 0x20000L,
|
||||
Opaque = 0x40000L,
|
||||
Pressed = 0x80000L,
|
||||
Resizable = 0x100000L,
|
||||
Selectable = 0x200000L,
|
||||
Selected = 0x400000L,
|
||||
Sensitive = 0x800000L,
|
||||
Showing = 0x1000000L,
|
||||
SingleLine = 0x2000000L,
|
||||
Stale = 0x4000000L,
|
||||
Transient = 0x8000000L,
|
||||
Vertical = 0x10000000L,
|
||||
Visible = 0x20000000L,
|
||||
ManagesDescendants = 0x40000000L,
|
||||
Indeterminate = 0x80000000L,
|
||||
Required = 0x100000000L,
|
||||
Truncated = 0x200000000L,
|
||||
Animated = 0x400000000L,
|
||||
InvalidEntry = 0x800000000L,
|
||||
SupportsAutocompletion = 0x1000000000L,
|
||||
SelectableText = 0x2000000000L,
|
||||
IsDefault = 0x4000000000L,
|
||||
Visited = 0x8000000000L,
|
||||
ReadOnly = 0x10000000000L
|
||||
}
|
||||
10
Services/AnnouncementPriority.cs
Normal file
10
Services/AnnouncementPriority.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum AnnouncementPriority
|
||||
{
|
||||
Polite,
|
||||
Assertive
|
||||
}
|
||||
@@ -134,10 +134,6 @@ public class AppActionsService : IAppActions
|
||||
}
|
||||
|
||||
content.AppendLine($"Exec={execPath} --action={action.Id}");
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
content.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,74 +388,3 @@ public class AtSpi2AccessibilityService : IAccessibilityService, IDisposable
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Factory for creating accessibility service instances.
|
||||
/// </summary>
|
||||
public static class AccessibilityServiceFactory
|
||||
{
|
||||
private static IAccessibilityService? _instance;
|
||||
private static readonly object _lock = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the singleton accessibility service instance.
|
||||
/// </summary>
|
||||
public static IAccessibilityService Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_instance ??= CreateService();
|
||||
}
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
private static IAccessibilityService CreateService()
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new AtSpi2AccessibilityService();
|
||||
service.Initialize();
|
||||
return service;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"AccessibilityServiceFactory: Failed to create AT-SPI2 service - {ex.Message}");
|
||||
return new NullAccessibilityService();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the singleton instance.
|
||||
/// </summary>
|
||||
public static void Reset()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_instance?.Shutdown();
|
||||
_instance = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Null implementation of accessibility service.
|
||||
/// </summary>
|
||||
public class NullAccessibilityService : IAccessibilityService
|
||||
{
|
||||
public bool IsEnabled => false;
|
||||
|
||||
public void Initialize() { }
|
||||
public void Register(IAccessible accessible) { }
|
||||
public void Unregister(IAccessible accessible) { }
|
||||
public void NotifyFocusChanged(IAccessible? accessible) { }
|
||||
public void NotifyPropertyChanged(IAccessible accessible, AccessibleProperty property) { }
|
||||
public void NotifyStateChanged(IAccessible accessible, AccessibleState state, bool value) { }
|
||||
public void Announce(string text, AnnouncementPriority priority = AnnouncementPriority.Polite) { }
|
||||
public void Shutdown() { }
|
||||
}
|
||||
|
||||
13
Services/ColorDialogResult.cs
Normal file
13
Services/ColorDialogResult.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class ColorDialogResult
|
||||
{
|
||||
public bool Accepted { get; init; }
|
||||
public float Red { get; init; }
|
||||
public float Green { get; init; }
|
||||
public float Blue { get; init; }
|
||||
public float Alpha { get; init; }
|
||||
}
|
||||
16
Services/DesktopEnvironment.cs
Normal file
16
Services/DesktopEnvironment.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum DesktopEnvironment
|
||||
{
|
||||
Unknown,
|
||||
GNOME,
|
||||
KDE,
|
||||
XFCE,
|
||||
MATE,
|
||||
Cinnamon,
|
||||
LXQt,
|
||||
LXDE
|
||||
}
|
||||
@@ -7,20 +7,6 @@ using Microsoft.Maui.Platform.Linux.Rendering;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Supported display server types.
|
||||
/// </summary>
|
||||
public enum DisplayServerType
|
||||
{
|
||||
Auto,
|
||||
X11,
|
||||
Wayland
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Factory for creating display server connections.
|
||||
/// Supports X11 and Wayland display servers.
|
||||
/// </summary>
|
||||
public static class DisplayServerFactory
|
||||
{
|
||||
private static DisplayServerType? _cachedServerType;
|
||||
@@ -139,136 +125,3 @@ public static class DisplayServerFactory
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Common interface for display server windows.
|
||||
/// </summary>
|
||||
public interface IDisplayWindow : IDisposable
|
||||
{
|
||||
int Width { get; }
|
||||
int Height { get; }
|
||||
bool IsRunning { get; }
|
||||
void Show();
|
||||
void Hide();
|
||||
void SetTitle(string title);
|
||||
void Resize(int width, int height);
|
||||
void ProcessEvents();
|
||||
void Stop();
|
||||
event EventHandler<KeyEventArgs>? KeyDown;
|
||||
event EventHandler<KeyEventArgs>? KeyUp;
|
||||
event EventHandler<TextInputEventArgs>? TextInput;
|
||||
event EventHandler<PointerEventArgs>? PointerMoved;
|
||||
event EventHandler<PointerEventArgs>? PointerPressed;
|
||||
event EventHandler<PointerEventArgs>? PointerReleased;
|
||||
event EventHandler<ScrollEventArgs>? Scroll;
|
||||
event EventHandler? Exposed;
|
||||
event EventHandler<(int Width, int Height)>? Resized;
|
||||
event EventHandler? CloseRequested;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// X11 display window wrapper implementing the common interface.
|
||||
/// </summary>
|
||||
public class X11DisplayWindow : IDisplayWindow
|
||||
{
|
||||
private readonly X11Window _window;
|
||||
|
||||
public int Width => _window.Width;
|
||||
public int Height => _window.Height;
|
||||
public bool IsRunning => _window.IsRunning;
|
||||
|
||||
public event EventHandler<KeyEventArgs>? KeyDown;
|
||||
public event EventHandler<KeyEventArgs>? KeyUp;
|
||||
public event EventHandler<TextInputEventArgs>? TextInput;
|
||||
public event EventHandler<PointerEventArgs>? PointerMoved;
|
||||
public event EventHandler<PointerEventArgs>? PointerPressed;
|
||||
public event EventHandler<PointerEventArgs>? PointerReleased;
|
||||
public event EventHandler<ScrollEventArgs>? Scroll;
|
||||
public event EventHandler? Exposed;
|
||||
public event EventHandler<(int Width, int Height)>? Resized;
|
||||
public event EventHandler? CloseRequested;
|
||||
|
||||
public X11DisplayWindow(string title, int width, int height)
|
||||
{
|
||||
_window = new X11Window(title, width, height);
|
||||
|
||||
_window.KeyDown += (s, e) => KeyDown?.Invoke(this, e);
|
||||
_window.KeyUp += (s, e) => KeyUp?.Invoke(this, e);
|
||||
_window.TextInput += (s, e) => TextInput?.Invoke(this, e);
|
||||
_window.PointerMoved += (s, e) => PointerMoved?.Invoke(this, e);
|
||||
_window.PointerPressed += (s, e) => PointerPressed?.Invoke(this, e);
|
||||
_window.PointerReleased += (s, e) => PointerReleased?.Invoke(this, e);
|
||||
_window.Scroll += (s, e) => Scroll?.Invoke(this, e);
|
||||
_window.Exposed += (s, e) => Exposed?.Invoke(this, e);
|
||||
_window.Resized += (s, e) => Resized?.Invoke(this, e);
|
||||
_window.CloseRequested += (s, e) => CloseRequested?.Invoke(this, e);
|
||||
}
|
||||
|
||||
public void Show() => _window.Show();
|
||||
public void Hide() => _window.Hide();
|
||||
public void SetTitle(string title) => _window.SetTitle(title);
|
||||
public void Resize(int width, int height) => _window.Resize(width, height);
|
||||
public void ProcessEvents() => _window.ProcessEvents();
|
||||
public void Stop() => _window.Stop();
|
||||
public void Dispose() => _window.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wayland display window wrapper implementing IDisplayWindow.
|
||||
/// Uses the full WaylandWindow implementation with xdg-shell protocol.
|
||||
/// </summary>
|
||||
public class WaylandDisplayWindow : IDisplayWindow
|
||||
{
|
||||
private readonly WaylandWindow _window;
|
||||
|
||||
public int Width => _window.Width;
|
||||
public int Height => _window.Height;
|
||||
public bool IsRunning => _window.IsRunning;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the pixel data pointer for rendering.
|
||||
/// </summary>
|
||||
public IntPtr PixelData => _window.PixelData;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the stride (bytes per row) of the pixel buffer.
|
||||
/// </summary>
|
||||
public int Stride => _window.Stride;
|
||||
|
||||
public event EventHandler<KeyEventArgs>? KeyDown;
|
||||
public event EventHandler<KeyEventArgs>? KeyUp;
|
||||
public event EventHandler<TextInputEventArgs>? TextInput;
|
||||
public event EventHandler<PointerEventArgs>? PointerMoved;
|
||||
public event EventHandler<PointerEventArgs>? PointerPressed;
|
||||
public event EventHandler<PointerEventArgs>? PointerReleased;
|
||||
public event EventHandler<ScrollEventArgs>? Scroll;
|
||||
public event EventHandler? Exposed;
|
||||
public event EventHandler<(int Width, int Height)>? Resized;
|
||||
public event EventHandler? CloseRequested;
|
||||
|
||||
public WaylandDisplayWindow(string title, int width, int height)
|
||||
{
|
||||
_window = new WaylandWindow(title, width, height);
|
||||
|
||||
// Wire up events
|
||||
_window.KeyDown += (s, e) => KeyDown?.Invoke(this, e);
|
||||
_window.KeyUp += (s, e) => KeyUp?.Invoke(this, e);
|
||||
_window.TextInput += (s, e) => TextInput?.Invoke(this, e);
|
||||
_window.PointerMoved += (s, e) => PointerMoved?.Invoke(this, e);
|
||||
_window.PointerPressed += (s, e) => PointerPressed?.Invoke(this, e);
|
||||
_window.PointerReleased += (s, e) => PointerReleased?.Invoke(this, e);
|
||||
_window.Scroll += (s, e) => Scroll?.Invoke(this, e);
|
||||
_window.Exposed += (s, e) => Exposed?.Invoke(this, e);
|
||||
_window.Resized += (s, e) => Resized?.Invoke(this, e);
|
||||
_window.CloseRequested += (s, e) => CloseRequested?.Invoke(this, e);
|
||||
}
|
||||
|
||||
public void Show() => _window.Show();
|
||||
public void Hide() => _window.Hide();
|
||||
public void SetTitle(string title) => _window.SetTitle(title);
|
||||
public void Resize(int width, int height) => _window.Resize(width, height);
|
||||
public void ProcessEvents() => _window.ProcessEvents();
|
||||
public void Stop() => _window.Stop();
|
||||
public void CommitFrame() => _window.CommitFrame();
|
||||
public void Dispose() => _window.Dispose();
|
||||
}
|
||||
|
||||
11
Services/DisplayServerType.cs
Normal file
11
Services/DisplayServerType.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum DisplayServerType
|
||||
{
|
||||
Auto,
|
||||
X11,
|
||||
Wayland
|
||||
}
|
||||
12
Services/DragAction.cs
Normal file
12
Services/DragAction.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum DragAction
|
||||
{
|
||||
None,
|
||||
Copy,
|
||||
Move,
|
||||
Link
|
||||
}
|
||||
13
Services/DragData.cs
Normal file
13
Services/DragData.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class DragData
|
||||
{
|
||||
public nint SourceWindow { get; set; }
|
||||
public nint[] SupportedTypes { get; set; } = [];
|
||||
public string? Text { get; set; }
|
||||
public string[]? FilePaths { get; set; }
|
||||
public object? Data { get; set; }
|
||||
}
|
||||
@@ -402,115 +402,3 @@ public class DragDropService : IDisposable
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Contains data for a drag operation.
|
||||
/// </summary>
|
||||
public class DragData
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the source window.
|
||||
/// </summary>
|
||||
public nint SourceWindow { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the supported MIME types.
|
||||
/// </summary>
|
||||
public nint[] SupportedTypes { get; set; } = Array.Empty<nint>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the text data.
|
||||
/// </summary>
|
||||
public string? Text { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the file paths.
|
||||
/// </summary>
|
||||
public string[]? FilePaths { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets custom data.
|
||||
/// </summary>
|
||||
public object? Data { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event args for drag events.
|
||||
/// </summary>
|
||||
public class DragEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the drag data.
|
||||
/// </summary>
|
||||
public DragData Data { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the X coordinate.
|
||||
/// </summary>
|
||||
public int X { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Y coordinate.
|
||||
/// </summary>
|
||||
public int Y { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether the drop is accepted.
|
||||
/// </summary>
|
||||
public bool Accepted { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the allowed action.
|
||||
/// </summary>
|
||||
public DragAction AllowedAction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the accepted action.
|
||||
/// </summary>
|
||||
public DragAction AcceptedAction { get; set; } = DragAction.Copy;
|
||||
|
||||
public DragEventArgs(DragData data, int x, int y)
|
||||
{
|
||||
Data = data;
|
||||
X = x;
|
||||
Y = y;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event args for drop events.
|
||||
/// </summary>
|
||||
public class DropEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the drag data.
|
||||
/// </summary>
|
||||
public DragData Data { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the dropped data as string.
|
||||
/// </summary>
|
||||
public string? DroppedData { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether the drop was handled.
|
||||
/// </summary>
|
||||
public bool Handled { get; set; }
|
||||
|
||||
public DropEventArgs(DragData data, string? droppedData)
|
||||
{
|
||||
Data = data;
|
||||
DroppedData = droppedData;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drag action types.
|
||||
/// </summary>
|
||||
public enum DragAction
|
||||
{
|
||||
None,
|
||||
Copy,
|
||||
Move,
|
||||
Link
|
||||
}
|
||||
|
||||
21
Services/DragEventArgs.cs
Normal file
21
Services/DragEventArgs.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class DragEventArgs : EventArgs
|
||||
{
|
||||
public DragData Data { get; }
|
||||
public int X { get; }
|
||||
public int Y { get; }
|
||||
public bool Accepted { get; set; }
|
||||
public DragAction AllowedAction { get; set; }
|
||||
public DragAction AcceptedAction { get; set; } = DragAction.Copy;
|
||||
|
||||
public DragEventArgs(DragData data, int x, int y)
|
||||
{
|
||||
Data = data;
|
||||
X = x;
|
||||
Y = y;
|
||||
}
|
||||
}
|
||||
17
Services/DropEventArgs.cs
Normal file
17
Services/DropEventArgs.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class DropEventArgs : EventArgs
|
||||
{
|
||||
public DragData Data { get; }
|
||||
public string? DroppedData { get; }
|
||||
public bool Handled { get; set; }
|
||||
|
||||
public DropEventArgs(DragData data, string? droppedData)
|
||||
{
|
||||
Data = data;
|
||||
DroppedData = droppedData;
|
||||
}
|
||||
}
|
||||
11
Services/FileDialogResult.cs
Normal file
11
Services/FileDialogResult.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class FileDialogResult
|
||||
{
|
||||
public bool Accepted { get; init; }
|
||||
public string[] SelectedFiles { get; init; } = [];
|
||||
public string? SelectedFile => SelectedFiles.Length > 0 ? SelectedFiles[0] : null;
|
||||
}
|
||||
@@ -200,13 +200,3 @@ public class FilePickerService : IFilePicker
|
||||
return arg.Replace("\"", "\\\"").Replace("'", "\\'");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Linux-specific FileResult implementation.
|
||||
/// </summary>
|
||||
internal class LinuxFileResult : FileResult
|
||||
{
|
||||
public LinuxFileResult(string fullPath) : base(fullPath)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
10
Services/FolderPickerOptions.cs
Normal file
10
Services/FolderPickerOptions.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class FolderPickerOptions
|
||||
{
|
||||
public string? Title { get; set; }
|
||||
public string? InitialDirectory { get; set; }
|
||||
}
|
||||
15
Services/FolderPickerResult.cs
Normal file
15
Services/FolderPickerResult.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class FolderPickerResult
|
||||
{
|
||||
public FolderResult? Folder { get; }
|
||||
public bool WasSuccessful => Folder != null;
|
||||
|
||||
public FolderPickerResult(FolderResult? folder)
|
||||
{
|
||||
Folder = folder;
|
||||
}
|
||||
}
|
||||
15
Services/FolderResult.cs
Normal file
15
Services/FolderResult.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class FolderResult
|
||||
{
|
||||
public string Path { get; }
|
||||
public string Name => System.IO.Path.GetFileName(Path) ?? Path;
|
||||
|
||||
public FolderResult(string path)
|
||||
{
|
||||
Path = path;
|
||||
}
|
||||
}
|
||||
@@ -256,37 +256,6 @@ public class FontFallbackManager
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a run of text with a specific typeface.
|
||||
/// </summary>
|
||||
public class TextRun
|
||||
{
|
||||
/// <summary>
|
||||
/// The text content of this run.
|
||||
/// </summary>
|
||||
public string Text { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The typeface to use for this run.
|
||||
/// </summary>
|
||||
public SKTypeface Typeface { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The starting character index in the original string.
|
||||
/// </summary>
|
||||
public int StartIndex { get; }
|
||||
|
||||
public TextRun(string text, SKTypeface typeface, int startIndex)
|
||||
{
|
||||
Text = text;
|
||||
Typeface = typeface;
|
||||
StartIndex = startIndex;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// StringBuilder for internal use.
|
||||
/// </summary>
|
||||
file class StringBuilder
|
||||
{
|
||||
private readonly List<char> _chars = new();
|
||||
|
||||
@@ -296,98 +296,3 @@ public class GlobalHotkeyService : IDisposable
|
||||
public HotkeyModifiers ModifierKeys { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event args for hotkey pressed events.
|
||||
/// </summary>
|
||||
public class HotkeyEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the registration ID.
|
||||
/// </summary>
|
||||
public int Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the key.
|
||||
/// </summary>
|
||||
public HotkeyKey Key { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the modifier keys.
|
||||
/// </summary>
|
||||
public HotkeyModifiers Modifiers { get; }
|
||||
|
||||
public HotkeyEventArgs(int id, HotkeyKey key, HotkeyModifiers modifiers)
|
||||
{
|
||||
Id = id;
|
||||
Key = key;
|
||||
Modifiers = modifiers;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hotkey modifier keys.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum HotkeyModifiers
|
||||
{
|
||||
None = 0,
|
||||
Shift = 1 << 0,
|
||||
Control = 1 << 1,
|
||||
Alt = 1 << 2,
|
||||
Super = 1 << 3
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hotkey keys (X11 keysyms).
|
||||
/// </summary>
|
||||
public enum HotkeyKey : uint
|
||||
{
|
||||
// Letters
|
||||
A = 0x61, B = 0x62, C = 0x63, D = 0x64, E = 0x65,
|
||||
F = 0x66, G = 0x67, H = 0x68, I = 0x69, J = 0x6A,
|
||||
K = 0x6B, L = 0x6C, M = 0x6D, N = 0x6E, O = 0x6F,
|
||||
P = 0x70, Q = 0x71, R = 0x72, S = 0x73, T = 0x74,
|
||||
U = 0x75, V = 0x76, W = 0x77, X = 0x78, Y = 0x79,
|
||||
Z = 0x7A,
|
||||
|
||||
// Numbers
|
||||
D0 = 0x30, D1 = 0x31, D2 = 0x32, D3 = 0x33, D4 = 0x34,
|
||||
D5 = 0x35, D6 = 0x36, D7 = 0x37, D8 = 0x38, D9 = 0x39,
|
||||
|
||||
// Function keys
|
||||
F1 = 0xFFBE, F2 = 0xFFBF, F3 = 0xFFC0, F4 = 0xFFC1,
|
||||
F5 = 0xFFC2, F6 = 0xFFC3, F7 = 0xFFC4, F8 = 0xFFC5,
|
||||
F9 = 0xFFC6, F10 = 0xFFC7, F11 = 0xFFC8, F12 = 0xFFC9,
|
||||
|
||||
// Special keys
|
||||
Escape = 0xFF1B,
|
||||
Tab = 0xFF09,
|
||||
Return = 0xFF0D,
|
||||
Space = 0x20,
|
||||
BackSpace = 0xFF08,
|
||||
Delete = 0xFFFF,
|
||||
Insert = 0xFF63,
|
||||
Home = 0xFF50,
|
||||
End = 0xFF57,
|
||||
PageUp = 0xFF55,
|
||||
PageDown = 0xFF56,
|
||||
|
||||
// Arrow keys
|
||||
Left = 0xFF51,
|
||||
Up = 0xFF52,
|
||||
Right = 0xFF53,
|
||||
Down = 0xFF54,
|
||||
|
||||
// Media keys
|
||||
AudioPlay = 0x1008FF14,
|
||||
AudioStop = 0x1008FF15,
|
||||
AudioPrev = 0x1008FF16,
|
||||
AudioNext = 0x1008FF17,
|
||||
AudioMute = 0x1008FF12,
|
||||
AudioRaiseVolume = 0x1008FF13,
|
||||
AudioLowerVolume = 0x1008FF11,
|
||||
|
||||
// Print screen
|
||||
Print = 0xFF61
|
||||
}
|
||||
|
||||
@@ -5,86 +5,6 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
/// <summary>
|
||||
/// GTK4 dialog response codes.
|
||||
/// </summary>
|
||||
public enum GtkResponseType
|
||||
{
|
||||
None = -1,
|
||||
Reject = -2,
|
||||
Accept = -3,
|
||||
DeleteEvent = -4,
|
||||
Ok = -5,
|
||||
Cancel = -6,
|
||||
Close = -7,
|
||||
Yes = -8,
|
||||
No = -9,
|
||||
Apply = -10,
|
||||
Help = -11
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GTK4 message dialog types.
|
||||
/// </summary>
|
||||
public enum GtkMessageType
|
||||
{
|
||||
Info = 0,
|
||||
Warning = 1,
|
||||
Question = 2,
|
||||
Error = 3,
|
||||
Other = 4
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GTK4 button layouts for dialogs.
|
||||
/// </summary>
|
||||
public enum GtkButtonsType
|
||||
{
|
||||
None = 0,
|
||||
Ok = 1,
|
||||
Close = 2,
|
||||
Cancel = 3,
|
||||
YesNo = 4,
|
||||
OkCancel = 5
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GTK4 file chooser actions.
|
||||
/// </summary>
|
||||
public enum GtkFileChooserAction
|
||||
{
|
||||
Open = 0,
|
||||
Save = 1,
|
||||
SelectFolder = 2,
|
||||
CreateFolder = 3
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Result from a file dialog.
|
||||
/// </summary>
|
||||
public class FileDialogResult
|
||||
{
|
||||
public bool Accepted { get; init; }
|
||||
public string[] SelectedFiles { get; init; } = Array.Empty<string>();
|
||||
public string? SelectedFile => SelectedFiles.Length > 0 ? SelectedFiles[0] : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Result from a color dialog.
|
||||
/// </summary>
|
||||
public class ColorDialogResult
|
||||
{
|
||||
public bool Accepted { get; init; }
|
||||
public float Red { get; init; }
|
||||
public float Green { get; init; }
|
||||
public float Blue { get; init; }
|
||||
public float Alpha { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GTK4 interop layer for native Linux dialogs.
|
||||
/// Provides native file pickers, message boxes, and color choosers.
|
||||
/// </summary>
|
||||
public class Gtk4InteropService : IDisposable
|
||||
{
|
||||
#region GTK4 Native Interop
|
||||
|
||||
14
Services/GtkButtonsType.cs
Normal file
14
Services/GtkButtonsType.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum GtkButtonsType
|
||||
{
|
||||
None,
|
||||
Ok,
|
||||
Close,
|
||||
Cancel,
|
||||
YesNo,
|
||||
OkCancel
|
||||
}
|
||||
12
Services/GtkFileChooserAction.cs
Normal file
12
Services/GtkFileChooserAction.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum GtkFileChooserAction
|
||||
{
|
||||
Open,
|
||||
Save,
|
||||
SelectFolder,
|
||||
CreateFolder
|
||||
}
|
||||
13
Services/GtkMessageType.cs
Normal file
13
Services/GtkMessageType.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum GtkMessageType
|
||||
{
|
||||
Info,
|
||||
Warning,
|
||||
Question,
|
||||
Error,
|
||||
Other
|
||||
}
|
||||
19
Services/GtkResponseType.cs
Normal file
19
Services/GtkResponseType.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum GtkResponseType
|
||||
{
|
||||
None = -1,
|
||||
Reject = -2,
|
||||
Accept = -3,
|
||||
DeleteEvent = -4,
|
||||
Ok = -5,
|
||||
Cancel = -6,
|
||||
Close = -7,
|
||||
Yes = -8,
|
||||
No = -9,
|
||||
Apply = -10,
|
||||
Help = -11
|
||||
}
|
||||
@@ -6,83 +6,6 @@ using SkiaSharp;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Supported hardware video acceleration APIs.
|
||||
/// </summary>
|
||||
public enum VideoAccelerationApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Automatically select the best available API.
|
||||
/// </summary>
|
||||
Auto,
|
||||
|
||||
/// <summary>
|
||||
/// VA-API (Video Acceleration API) - Intel, AMD, and some NVIDIA.
|
||||
/// </summary>
|
||||
VaApi,
|
||||
|
||||
/// <summary>
|
||||
/// VDPAU (Video Decode and Presentation API for Unix) - NVIDIA.
|
||||
/// </summary>
|
||||
Vdpau,
|
||||
|
||||
/// <summary>
|
||||
/// Software decoding fallback.
|
||||
/// </summary>
|
||||
Software
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Video codec profiles supported by hardware acceleration.
|
||||
/// </summary>
|
||||
public enum VideoProfile
|
||||
{
|
||||
H264Baseline,
|
||||
H264Main,
|
||||
H264High,
|
||||
H265Main,
|
||||
H265Main10,
|
||||
Vp8,
|
||||
Vp9Profile0,
|
||||
Vp9Profile2,
|
||||
Av1Main
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Information about a decoded video frame.
|
||||
/// </summary>
|
||||
public class VideoFrame : IDisposable
|
||||
{
|
||||
public int Width { get; init; }
|
||||
public int Height { get; init; }
|
||||
public IntPtr DataY { get; init; }
|
||||
public IntPtr DataU { get; init; }
|
||||
public IntPtr DataV { get; init; }
|
||||
public int StrideY { get; init; }
|
||||
public int StrideU { get; init; }
|
||||
public int StrideV { get; init; }
|
||||
public long Timestamp { get; init; }
|
||||
public bool IsKeyFrame { get; init; }
|
||||
|
||||
private bool _disposed;
|
||||
private Action? _releaseCallback;
|
||||
|
||||
internal void SetReleaseCallback(Action callback) => _releaseCallback = callback;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
_releaseCallback?.Invoke();
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hardware-accelerated video decoding service using VA-API or VDPAU.
|
||||
/// Provides efficient video decode for media playback on Linux.
|
||||
/// </summary>
|
||||
public class HardwareVideoService : IDisposable
|
||||
{
|
||||
#region VA-API Native Interop
|
||||
|
||||
@@ -494,31 +494,3 @@ public class HiDpiService
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event args for scale change events.
|
||||
/// </summary>
|
||||
public class ScaleChangedEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the old scale factor.
|
||||
/// </summary>
|
||||
public float OldScale { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the new scale factor.
|
||||
/// </summary>
|
||||
public float NewScale { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the new DPI.
|
||||
/// </summary>
|
||||
public float NewDpi { get; }
|
||||
|
||||
public ScaleChangedEventArgs(float oldScale, float newScale, float newDpi)
|
||||
{
|
||||
OldScale = oldScale;
|
||||
NewScale = newScale;
|
||||
NewDpi = newDpi;
|
||||
}
|
||||
}
|
||||
|
||||
17
Services/HighContrastChangedEventArgs.cs
Normal file
17
Services/HighContrastChangedEventArgs.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class HighContrastChangedEventArgs : EventArgs
|
||||
{
|
||||
public bool IsEnabled { get; }
|
||||
|
||||
public HighContrastTheme Theme { get; }
|
||||
|
||||
public HighContrastChangedEventArgs(bool isEnabled, HighContrastTheme theme)
|
||||
{
|
||||
IsEnabled = isEnabled;
|
||||
Theme = theme;
|
||||
}
|
||||
}
|
||||
35
Services/HighContrastColors.cs
Normal file
35
Services/HighContrastColors.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class HighContrastColors
|
||||
{
|
||||
public SKColor Background { get; set; }
|
||||
|
||||
public SKColor Foreground { get; set; }
|
||||
|
||||
public SKColor Accent { get; set; }
|
||||
|
||||
public SKColor Border { get; set; }
|
||||
|
||||
public SKColor Error { get; set; }
|
||||
|
||||
public SKColor Success { get; set; }
|
||||
|
||||
public SKColor Warning { get; set; }
|
||||
|
||||
public SKColor Link { get; set; }
|
||||
|
||||
public SKColor LinkVisited { get; set; }
|
||||
|
||||
public SKColor Selection { get; set; }
|
||||
|
||||
public SKColor SelectionText { get; set; }
|
||||
|
||||
public SKColor DisabledText { get; set; }
|
||||
|
||||
public SKColor DisabledBackground { get; set; }
|
||||
}
|
||||
@@ -348,55 +348,3 @@ public class HighContrastService
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// High contrast theme types.
|
||||
/// </summary>
|
||||
public enum HighContrastTheme
|
||||
{
|
||||
None,
|
||||
WhiteOnBlack,
|
||||
BlackOnWhite
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Color palette for high contrast mode.
|
||||
/// </summary>
|
||||
public class HighContrastColors
|
||||
{
|
||||
public SKColor Background { get; set; }
|
||||
public SKColor Foreground { get; set; }
|
||||
public SKColor Accent { get; set; }
|
||||
public SKColor Border { get; set; }
|
||||
public SKColor Error { get; set; }
|
||||
public SKColor Success { get; set; }
|
||||
public SKColor Warning { get; set; }
|
||||
public SKColor Link { get; set; }
|
||||
public SKColor LinkVisited { get; set; }
|
||||
public SKColor Selection { get; set; }
|
||||
public SKColor SelectionText { get; set; }
|
||||
public SKColor DisabledText { get; set; }
|
||||
public SKColor DisabledBackground { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event args for high contrast mode changes.
|
||||
/// </summary>
|
||||
public class HighContrastChangedEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets whether high contrast mode is enabled.
|
||||
/// </summary>
|
||||
public bool IsEnabled { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current theme.
|
||||
/// </summary>
|
||||
public HighContrastTheme Theme { get; }
|
||||
|
||||
public HighContrastChangedEventArgs(bool isEnabled, HighContrastTheme theme)
|
||||
{
|
||||
IsEnabled = isEnabled;
|
||||
Theme = theme;
|
||||
}
|
||||
}
|
||||
|
||||
11
Services/HighContrastTheme.cs
Normal file
11
Services/HighContrastTheme.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum HighContrastTheme
|
||||
{
|
||||
None,
|
||||
WhiteOnBlack,
|
||||
BlackOnWhite
|
||||
}
|
||||
18
Services/HotkeyEventArgs.cs
Normal file
18
Services/HotkeyEventArgs.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class HotkeyEventArgs : EventArgs
|
||||
{
|
||||
public int Id { get; }
|
||||
public HotkeyKey Key { get; }
|
||||
public HotkeyModifiers Modifiers { get; }
|
||||
|
||||
public HotkeyEventArgs(int id, HotkeyKey key, HotkeyModifiers modifiers)
|
||||
{
|
||||
Id = id;
|
||||
Key = key;
|
||||
Modifiers = modifiers;
|
||||
}
|
||||
}
|
||||
17
Services/HotkeyKey.cs
Normal file
17
Services/HotkeyKey.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum HotkeyKey
|
||||
{
|
||||
None,
|
||||
A, B, C, D, E, F, G, H, I, J, K, L, M,
|
||||
N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
|
||||
D0, D1, D2, D3, D4, D5, D6, D7, D8, D9,
|
||||
F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
|
||||
Space, Enter, Escape, Tab, Backspace, Delete, Insert,
|
||||
Home, End, PageUp, PageDown,
|
||||
Left, Right, Up, Down,
|
||||
PrintScreen, Pause, NumLock, ScrollLock, CapsLock
|
||||
}
|
||||
14
Services/HotkeyModifiers.cs
Normal file
14
Services/HotkeyModifiers.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
[Flags]
|
||||
public enum HotkeyModifiers
|
||||
{
|
||||
None = 0,
|
||||
Alt = 1,
|
||||
Control = 2,
|
||||
Shift = 4,
|
||||
Super = 8
|
||||
}
|
||||
@@ -64,373 +64,3 @@ public interface IAccessibilityService
|
||||
/// </summary>
|
||||
void Shutdown();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface for accessible objects.
|
||||
/// </summary>
|
||||
public interface IAccessible
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the unique identifier for this accessible.
|
||||
/// </summary>
|
||||
string AccessibleId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the accessible name (label for screen readers).
|
||||
/// </summary>
|
||||
string AccessibleName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the accessible description (additional context).
|
||||
/// </summary>
|
||||
string AccessibleDescription { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the accessible role.
|
||||
/// </summary>
|
||||
AccessibleRole Role { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the accessible states.
|
||||
/// </summary>
|
||||
AccessibleStates States { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parent accessible.
|
||||
/// </summary>
|
||||
IAccessible? Parent { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the child accessibles.
|
||||
/// </summary>
|
||||
IReadOnlyList<IAccessible> Children { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bounding rectangle in screen coordinates.
|
||||
/// </summary>
|
||||
AccessibleRect Bounds { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the available actions.
|
||||
/// </summary>
|
||||
IReadOnlyList<AccessibleAction> Actions { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Performs an action.
|
||||
/// </summary>
|
||||
/// <param name="actionName">The name of the action to perform.</param>
|
||||
/// <returns>True if the action was performed.</returns>
|
||||
bool DoAction(string actionName);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the accessible value (for sliders, progress bars, etc.).
|
||||
/// </summary>
|
||||
double? Value { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the minimum value.
|
||||
/// </summary>
|
||||
double? MinValue { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum value.
|
||||
/// </summary>
|
||||
double? MaxValue { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the accessible value.
|
||||
/// </summary>
|
||||
bool SetValue(double value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface for accessible text components.
|
||||
/// </summary>
|
||||
public interface IAccessibleText : IAccessible
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the text content.
|
||||
/// </summary>
|
||||
string Text { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the caret offset.
|
||||
/// </summary>
|
||||
int CaretOffset { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of selections.
|
||||
/// </summary>
|
||||
int SelectionCount { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the selection at the specified index.
|
||||
/// </summary>
|
||||
(int Start, int End) GetSelection(int index);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the selection.
|
||||
/// </summary>
|
||||
bool SetSelection(int index, int start, int end);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the character at the specified offset.
|
||||
/// </summary>
|
||||
char GetCharacterAtOffset(int offset);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the text in the specified range.
|
||||
/// </summary>
|
||||
string GetTextInRange(int start, int end);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bounds of the character at the specified offset.
|
||||
/// </summary>
|
||||
AccessibleRect GetCharacterBounds(int offset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface for editable text components.
|
||||
/// </summary>
|
||||
public interface IAccessibleEditableText : IAccessibleText
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the text content.
|
||||
/// </summary>
|
||||
bool SetText(string text);
|
||||
|
||||
/// <summary>
|
||||
/// Inserts text at the specified position.
|
||||
/// </summary>
|
||||
bool InsertText(int position, string text);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes text in the specified range.
|
||||
/// </summary>
|
||||
bool DeleteText(int start, int end);
|
||||
|
||||
/// <summary>
|
||||
/// Copies text to clipboard.
|
||||
/// </summary>
|
||||
bool CopyText(int start, int end);
|
||||
|
||||
/// <summary>
|
||||
/// Cuts text to clipboard.
|
||||
/// </summary>
|
||||
bool CutText(int start, int end);
|
||||
|
||||
/// <summary>
|
||||
/// Pastes text from clipboard.
|
||||
/// </summary>
|
||||
bool PasteText(int position);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Accessible roles (based on AT-SPI2 roles).
|
||||
/// </summary>
|
||||
public enum AccessibleRole
|
||||
{
|
||||
Unknown,
|
||||
Window,
|
||||
Application,
|
||||
Panel,
|
||||
Frame,
|
||||
Button,
|
||||
CheckBox,
|
||||
RadioButton,
|
||||
ComboBox,
|
||||
Entry,
|
||||
Label,
|
||||
List,
|
||||
ListItem,
|
||||
Menu,
|
||||
MenuBar,
|
||||
MenuItem,
|
||||
ScrollBar,
|
||||
Slider,
|
||||
SpinButton,
|
||||
StatusBar,
|
||||
Tab,
|
||||
TabPanel,
|
||||
Text,
|
||||
ToggleButton,
|
||||
ToolBar,
|
||||
ToolTip,
|
||||
Tree,
|
||||
TreeItem,
|
||||
Image,
|
||||
ProgressBar,
|
||||
Separator,
|
||||
Link,
|
||||
Table,
|
||||
TableCell,
|
||||
TableRow,
|
||||
TableColumnHeader,
|
||||
TableRowHeader,
|
||||
PageTab,
|
||||
PageTabList,
|
||||
Dialog,
|
||||
Alert,
|
||||
Filler,
|
||||
Icon,
|
||||
Canvas
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Accessible states.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum AccessibleStates : long
|
||||
{
|
||||
None = 0,
|
||||
Active = 1L << 0,
|
||||
Armed = 1L << 1,
|
||||
Busy = 1L << 2,
|
||||
Checked = 1L << 3,
|
||||
Collapsed = 1L << 4,
|
||||
Defunct = 1L << 5,
|
||||
Editable = 1L << 6,
|
||||
Enabled = 1L << 7,
|
||||
Expandable = 1L << 8,
|
||||
Expanded = 1L << 9,
|
||||
Focusable = 1L << 10,
|
||||
Focused = 1L << 11,
|
||||
HasToolTip = 1L << 12,
|
||||
Horizontal = 1L << 13,
|
||||
Iconified = 1L << 14,
|
||||
Modal = 1L << 15,
|
||||
MultiLine = 1L << 16,
|
||||
MultiSelectable = 1L << 17,
|
||||
Opaque = 1L << 18,
|
||||
Pressed = 1L << 19,
|
||||
Resizable = 1L << 20,
|
||||
Selectable = 1L << 21,
|
||||
Selected = 1L << 22,
|
||||
Sensitive = 1L << 23,
|
||||
Showing = 1L << 24,
|
||||
SingleLine = 1L << 25,
|
||||
Stale = 1L << 26,
|
||||
Transient = 1L << 27,
|
||||
Vertical = 1L << 28,
|
||||
Visible = 1L << 29,
|
||||
ManagesDescendants = 1L << 30,
|
||||
Indeterminate = 1L << 31,
|
||||
Required = 1L << 32,
|
||||
Truncated = 1L << 33,
|
||||
Animated = 1L << 34,
|
||||
InvalidEntry = 1L << 35,
|
||||
SupportsAutocompletion = 1L << 36,
|
||||
SelectableText = 1L << 37,
|
||||
IsDefault = 1L << 38,
|
||||
Visited = 1L << 39,
|
||||
ReadOnly = 1L << 40
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Accessible state enumeration for notifications.
|
||||
/// </summary>
|
||||
public enum AccessibleState
|
||||
{
|
||||
Active,
|
||||
Armed,
|
||||
Busy,
|
||||
Checked,
|
||||
Collapsed,
|
||||
Defunct,
|
||||
Editable,
|
||||
Enabled,
|
||||
Expandable,
|
||||
Expanded,
|
||||
Focusable,
|
||||
Focused,
|
||||
Horizontal,
|
||||
Iconified,
|
||||
Modal,
|
||||
MultiLine,
|
||||
Opaque,
|
||||
Pressed,
|
||||
Resizable,
|
||||
Selectable,
|
||||
Selected,
|
||||
Sensitive,
|
||||
Showing,
|
||||
SingleLine,
|
||||
Stale,
|
||||
Transient,
|
||||
Vertical,
|
||||
Visible,
|
||||
ManagesDescendants,
|
||||
Indeterminate,
|
||||
Required,
|
||||
InvalidEntry,
|
||||
ReadOnly
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Accessible property for notifications.
|
||||
/// </summary>
|
||||
public enum AccessibleProperty
|
||||
{
|
||||
Name,
|
||||
Description,
|
||||
Role,
|
||||
Value,
|
||||
Parent,
|
||||
Children
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Announcement priority.
|
||||
/// </summary>
|
||||
public enum AnnouncementPriority
|
||||
{
|
||||
/// <summary>
|
||||
/// Low priority - can be interrupted.
|
||||
/// </summary>
|
||||
Polite,
|
||||
|
||||
/// <summary>
|
||||
/// High priority - interrupts current speech.
|
||||
/// </summary>
|
||||
Assertive
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an accessible action.
|
||||
/// </summary>
|
||||
public class AccessibleAction
|
||||
{
|
||||
/// <summary>
|
||||
/// The action name.
|
||||
/// </summary>
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The action description.
|
||||
/// </summary>
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The keyboard shortcut for this action.
|
||||
/// </summary>
|
||||
public string? KeyBinding { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a rectangle in accessible coordinates.
|
||||
/// </summary>
|
||||
public struct AccessibleRect
|
||||
{
|
||||
public int X { get; set; }
|
||||
public int Y { get; set; }
|
||||
public int Width { get; set; }
|
||||
public int Height { get; set; }
|
||||
|
||||
public AccessibleRect(int x, int y, int width, int height)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Width = width;
|
||||
Height = height;
|
||||
}
|
||||
}
|
||||
|
||||
23
Services/IAccessible.cs
Normal file
23
Services/IAccessible.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public interface IAccessible
|
||||
{
|
||||
string AccessibleId { get; }
|
||||
string AccessibleName { get; }
|
||||
string AccessibleDescription { get; }
|
||||
AccessibleRole Role { get; }
|
||||
AccessibleStates States { get; }
|
||||
IAccessible? Parent { get; }
|
||||
IReadOnlyList<IAccessible> Children { get; }
|
||||
AccessibleRect Bounds { get; }
|
||||
IReadOnlyList<AccessibleAction> Actions { get; }
|
||||
double? Value { get; }
|
||||
double? MinValue { get; }
|
||||
double? MaxValue { get; }
|
||||
|
||||
bool DoAction(string actionName);
|
||||
bool SetValue(double value);
|
||||
}
|
||||
19
Services/IAccessibleEditableText.cs
Normal file
19
Services/IAccessibleEditableText.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public interface IAccessibleEditableText : IAccessibleText, IAccessible
|
||||
{
|
||||
bool SetText(string text);
|
||||
|
||||
bool InsertText(int position, string text);
|
||||
|
||||
bool DeleteText(int start, int end);
|
||||
|
||||
bool CopyText(int start, int end);
|
||||
|
||||
bool CutText(int start, int end);
|
||||
|
||||
bool PasteText(int position);
|
||||
}
|
||||
23
Services/IAccessibleText.cs
Normal file
23
Services/IAccessibleText.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public interface IAccessibleText : IAccessible
|
||||
{
|
||||
string Text { get; }
|
||||
|
||||
int CaretOffset { get; }
|
||||
|
||||
int SelectionCount { get; }
|
||||
|
||||
(int Start, int End) GetSelection(int index);
|
||||
|
||||
bool SetSelection(int index, int start, int end);
|
||||
|
||||
char GetCharacterAtOffset(int offset);
|
||||
|
||||
string GetTextInRange(int start, int end);
|
||||
|
||||
AccessibleRect GetCharacterBounds(int offset);
|
||||
}
|
||||
45
Services/IDisplayWindow.cs
Normal file
45
Services/IDisplayWindow.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public interface IDisplayWindow : IDisposable
|
||||
{
|
||||
int Width { get; }
|
||||
|
||||
int Height { get; }
|
||||
|
||||
bool IsRunning { get; }
|
||||
|
||||
event EventHandler<KeyEventArgs>? KeyDown;
|
||||
|
||||
event EventHandler<KeyEventArgs>? KeyUp;
|
||||
|
||||
event EventHandler<TextInputEventArgs>? TextInput;
|
||||
|
||||
event EventHandler<PointerEventArgs>? PointerMoved;
|
||||
|
||||
event EventHandler<PointerEventArgs>? PointerPressed;
|
||||
|
||||
event EventHandler<PointerEventArgs>? PointerReleased;
|
||||
|
||||
event EventHandler<ScrollEventArgs>? Scroll;
|
||||
|
||||
event EventHandler? Exposed;
|
||||
|
||||
event EventHandler<(int Width, int Height)>? Resized;
|
||||
|
||||
event EventHandler? CloseRequested;
|
||||
|
||||
void Show();
|
||||
|
||||
void Hide();
|
||||
|
||||
void SetTitle(string title);
|
||||
|
||||
void Resize(int width, int height);
|
||||
|
||||
void ProcessEvents();
|
||||
|
||||
void Stop();
|
||||
}
|
||||
21
Services/IInputContext.cs
Normal file
21
Services/IInputContext.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public interface IInputContext
|
||||
{
|
||||
string Text { get; set; }
|
||||
|
||||
int CursorPosition { get; set; }
|
||||
|
||||
int SelectionStart { get; }
|
||||
|
||||
int SelectionLength { get; }
|
||||
|
||||
void OnTextCommitted(string text);
|
||||
|
||||
void OnPreEditChanged(string preEditText, int cursorPosition);
|
||||
|
||||
void OnPreEditEnded();
|
||||
}
|
||||
@@ -79,153 +79,3 @@ public interface IInputMethodService
|
||||
/// </summary>
|
||||
event EventHandler? PreEditEnded;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an input context that can receive IME input.
|
||||
/// </summary>
|
||||
public interface IInputContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the current text content.
|
||||
/// </summary>
|
||||
string Text { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the cursor position.
|
||||
/// </summary>
|
||||
int CursorPosition { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the selection start position.
|
||||
/// </summary>
|
||||
int SelectionStart { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the selection length.
|
||||
/// </summary>
|
||||
int SelectionLength { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Called when text is committed from the IME.
|
||||
/// </summary>
|
||||
/// <param name="text">The committed text.</param>
|
||||
void OnTextCommitted(string text);
|
||||
|
||||
/// <summary>
|
||||
/// Called when pre-edit text changes.
|
||||
/// </summary>
|
||||
/// <param name="preEditText">The current pre-edit text.</param>
|
||||
/// <param name="cursorPosition">Cursor position within pre-edit text.</param>
|
||||
void OnPreEditChanged(string preEditText, int cursorPosition);
|
||||
|
||||
/// <summary>
|
||||
/// Called when pre-edit mode ends.
|
||||
/// </summary>
|
||||
void OnPreEditEnded();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event args for text committed events.
|
||||
/// </summary>
|
||||
public class TextCommittedEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The committed text.
|
||||
/// </summary>
|
||||
public string Text { get; }
|
||||
|
||||
public TextCommittedEventArgs(string text)
|
||||
{
|
||||
Text = text;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event args for pre-edit changed events.
|
||||
/// </summary>
|
||||
public class PreEditChangedEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The current pre-edit text.
|
||||
/// </summary>
|
||||
public string PreEditText { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Cursor position within the pre-edit text.
|
||||
/// </summary>
|
||||
public int CursorPosition { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Formatting attributes for the pre-edit text.
|
||||
/// </summary>
|
||||
public IReadOnlyList<PreEditAttribute> Attributes { get; }
|
||||
|
||||
public PreEditChangedEventArgs(string preEditText, int cursorPosition, IReadOnlyList<PreEditAttribute>? attributes = null)
|
||||
{
|
||||
PreEditText = preEditText;
|
||||
CursorPosition = cursorPosition;
|
||||
Attributes = attributes ?? Array.Empty<PreEditAttribute>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents formatting for a portion of pre-edit text.
|
||||
/// </summary>
|
||||
public class PreEditAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Start position in the pre-edit text.
|
||||
/// </summary>
|
||||
public int Start { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Length of the attributed range.
|
||||
/// </summary>
|
||||
public int Length { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The attribute type.
|
||||
/// </summary>
|
||||
public PreEditAttributeType Type { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Types of pre-edit text attributes.
|
||||
/// </summary>
|
||||
public enum PreEditAttributeType
|
||||
{
|
||||
/// <summary>
|
||||
/// Normal text (no special formatting).
|
||||
/// </summary>
|
||||
None,
|
||||
|
||||
/// <summary>
|
||||
/// Underlined text (typical for composition).
|
||||
/// </summary>
|
||||
Underline,
|
||||
|
||||
/// <summary>
|
||||
/// Highlighted/selected text.
|
||||
/// </summary>
|
||||
Highlighted,
|
||||
|
||||
/// <summary>
|
||||
/// Reverse video (selected clause in some IMEs).
|
||||
/// </summary>
|
||||
Reverse
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Key modifiers for IME processing.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum KeyModifiers
|
||||
{
|
||||
None = 0,
|
||||
Shift = 1 << 0,
|
||||
Control = 1 << 1,
|
||||
Alt = 1 << 2,
|
||||
Super = 1 << 3,
|
||||
CapsLock = 1 << 4,
|
||||
NumLock = 1 << 5
|
||||
}
|
||||
|
||||
@@ -180,24 +180,3 @@ public static class InputMethodServiceFactory
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Null implementation of IInputMethodService for when no IME is available.
|
||||
/// </summary>
|
||||
public class NullInputMethodService : IInputMethodService
|
||||
{
|
||||
public bool IsActive => false;
|
||||
public string PreEditText => string.Empty;
|
||||
public int PreEditCursorPosition => 0;
|
||||
|
||||
public event EventHandler<TextCommittedEventArgs>? TextCommitted;
|
||||
public event EventHandler<PreEditChangedEventArgs>? PreEditChanged;
|
||||
public event EventHandler? PreEditEnded;
|
||||
|
||||
public void Initialize(nint windowHandle) { }
|
||||
public void SetFocus(IInputContext? context) { }
|
||||
public void SetCursorLocation(int x, int y, int width, int height) { }
|
||||
public bool ProcessKeyEvent(uint keyCode, KeyModifiers modifiers, bool isKeyDown) => false;
|
||||
public void Reset() { }
|
||||
public void Shutdown() { }
|
||||
}
|
||||
|
||||
16
Services/KeyModifiers.cs
Normal file
16
Services/KeyModifiers.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
[Flags]
|
||||
public enum KeyModifiers
|
||||
{
|
||||
None = 0,
|
||||
Shift = 1,
|
||||
Control = 2,
|
||||
Alt = 4,
|
||||
Super = 8,
|
||||
CapsLock = 0x10,
|
||||
NumLock = 0x20
|
||||
}
|
||||
14
Services/LinuxFileResult.cs
Normal file
14
Services/LinuxFileResult.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using Microsoft.Maui.Storage;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
internal class LinuxFileResult : FileResult
|
||||
{
|
||||
public LinuxFileResult(string fullPath)
|
||||
: base(fullPath)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -3,13 +3,13 @@ using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using SkiaSharp;
|
||||
using Svg.Skia;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Generates application icons from MAUI icon metadata.
|
||||
/// Creates PNG icons suitable for use as window icons on Linux.
|
||||
/// Note: SVG overlay support requires Svg.Skia package (optional).
|
||||
/// Uses SVG overlay support via Svg.Skia package.
|
||||
/// </summary>
|
||||
public static class MauiIconGenerator
|
||||
{
|
||||
@@ -28,50 +28,52 @@ public static class MauiIconGenerator
|
||||
string path = Path.GetDirectoryName(metaFilePath) ?? "";
|
||||
var metadata = ParseMetadata(File.ReadAllText(metaFilePath));
|
||||
|
||||
// bg and fg paths (bg not currently used, but available for future)
|
||||
Path.Combine(path, "appicon_bg.svg");
|
||||
string fgPath = Path.Combine(path, "appicon_fg.svg");
|
||||
string outputPath = Path.Combine(path, "appicon.png");
|
||||
|
||||
// Parse size from metadata or use default
|
||||
int size = metadata.TryGetValue("Size", out var sizeStr) && int.TryParse(sizeStr, out var sizeVal)
|
||||
? sizeVal
|
||||
: DefaultIconSize;
|
||||
|
||||
// Parse color from metadata or use default purple
|
||||
SKColor color = metadata.TryGetValue("Color", out var colorStr)
|
||||
? ParseColor(colorStr)
|
||||
: SKColors.Purple;
|
||||
|
||||
// Parse scale from metadata or use default 0.65
|
||||
float scale = metadata.TryGetValue("Scale", out var scaleStr) && float.TryParse(scaleStr, out var scaleVal)
|
||||
? scaleVal
|
||||
: 0.65f;
|
||||
|
||||
Console.WriteLine($"[MauiIconGenerator] Generating {size}x{size} icon");
|
||||
Console.WriteLine($"[MauiIconGenerator] Color: {color}");
|
||||
Console.WriteLine($"[MauiIconGenerator] Scale: {scale}");
|
||||
|
||||
using var surface = SKSurface.Create(new SKImageInfo(size, size, SKColorType.Bgra8888, SKAlphaType.Premul));
|
||||
var canvas = surface.Canvas;
|
||||
|
||||
// Draw background with rounded corners
|
||||
canvas.Clear(SKColors.Transparent);
|
||||
float cornerRadius = size * 0.2f;
|
||||
using var paint = new SKPaint { Color = color, IsAntialias = true };
|
||||
canvas.DrawRoundRect(new SKRoundRect(new SKRect(0, 0, size, size), cornerRadius), paint);
|
||||
// Fill background with color
|
||||
canvas.Clear(color);
|
||||
|
||||
// Try to load PNG foreground as fallback (appicon_fg.png)
|
||||
string fgPngPath = Path.Combine(path, "appicon_fg.png");
|
||||
if (File.Exists(fgPngPath))
|
||||
// Load and draw SVG foreground if it exists
|
||||
if (File.Exists(fgPath))
|
||||
{
|
||||
try
|
||||
using var svg = new SKSvg();
|
||||
if (svg.Load(fgPath) != null && svg.Picture != null)
|
||||
{
|
||||
using var fgBitmap = SKBitmap.Decode(fgPngPath);
|
||||
if (fgBitmap != null)
|
||||
{
|
||||
float scale = size * 0.65f / Math.Max(fgBitmap.Width, fgBitmap.Height);
|
||||
float fgWidth = fgBitmap.Width * scale;
|
||||
float fgHeight = fgBitmap.Height * scale;
|
||||
float offsetX = (size - fgWidth) / 2f;
|
||||
float offsetY = (size - fgHeight) / 2f;
|
||||
var cullRect = svg.Picture.CullRect;
|
||||
float svgScale = size * scale / Math.Max(cullRect.Width, cullRect.Height);
|
||||
float offsetX = (size - cullRect.Width * svgScale) / 2f;
|
||||
float offsetY = (size - cullRect.Height * svgScale) / 2f;
|
||||
|
||||
var dstRect = new SKRect(offsetX, offsetY, offsetX + fgWidth, offsetY + fgHeight);
|
||||
canvas.DrawBitmap(fgBitmap, dstRect);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("[MauiIconGenerator] Failed to load foreground PNG: " + ex.Message);
|
||||
canvas.Save();
|
||||
canvas.Translate(offsetX, offsetY);
|
||||
canvas.Scale(svgScale);
|
||||
canvas.DrawPicture(svg.Picture);
|
||||
canvas.Restore();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
24
Services/NotificationAction.cs
Normal file
24
Services/NotificationAction.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class NotificationAction
|
||||
{
|
||||
public string Key { get; set; } = "";
|
||||
|
||||
public string Label { get; set; } = "";
|
||||
|
||||
public Action? Callback { get; set; }
|
||||
|
||||
public NotificationAction()
|
||||
{
|
||||
}
|
||||
|
||||
public NotificationAction(string key, string label, Action? callback = null)
|
||||
{
|
||||
Key = key;
|
||||
Label = label;
|
||||
Callback = callback;
|
||||
}
|
||||
}
|
||||
20
Services/NotificationActionEventArgs.cs
Normal file
20
Services/NotificationActionEventArgs.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class NotificationActionEventArgs : EventArgs
|
||||
{
|
||||
public uint NotificationId { get; }
|
||||
|
||||
public string ActionKey { get; }
|
||||
|
||||
public string? Tag { get; }
|
||||
|
||||
public NotificationActionEventArgs(uint notificationId, string actionKey, string? tag)
|
||||
{
|
||||
NotificationId = notificationId;
|
||||
ActionKey = actionKey;
|
||||
Tag = tag;
|
||||
}
|
||||
}
|
||||
12
Services/NotificationCloseReason.cs
Normal file
12
Services/NotificationCloseReason.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum NotificationCloseReason
|
||||
{
|
||||
Expired = 1,
|
||||
Dismissed,
|
||||
Closed,
|
||||
Undefined
|
||||
}
|
||||
20
Services/NotificationClosedEventArgs.cs
Normal file
20
Services/NotificationClosedEventArgs.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class NotificationClosedEventArgs : EventArgs
|
||||
{
|
||||
public uint NotificationId { get; }
|
||||
|
||||
public NotificationCloseReason Reason { get; }
|
||||
|
||||
public string? Tag { get; }
|
||||
|
||||
public NotificationClosedEventArgs(uint notificationId, NotificationCloseReason reason, string? tag)
|
||||
{
|
||||
NotificationId = notificationId;
|
||||
Reason = reason;
|
||||
Tag = tag;
|
||||
}
|
||||
}
|
||||
11
Services/NotificationContext.cs
Normal file
11
Services/NotificationContext.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
internal class NotificationContext
|
||||
{
|
||||
public string? Tag { get; set; }
|
||||
|
||||
public Dictionary<string, Action?>? ActionCallbacks { get; set; }
|
||||
}
|
||||
25
Services/NotificationOptions.cs
Normal file
25
Services/NotificationOptions.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class NotificationOptions
|
||||
{
|
||||
public string Title { get; set; } = "";
|
||||
|
||||
public string Message { get; set; } = "";
|
||||
|
||||
public string? IconPath { get; set; }
|
||||
|
||||
public string? IconName { get; set; }
|
||||
|
||||
public NotificationUrgency Urgency { get; set; } = NotificationUrgency.Normal;
|
||||
|
||||
public int ExpireTimeMs { get; set; } = 5000;
|
||||
|
||||
public string? Category { get; set; }
|
||||
|
||||
public bool IsTransient { get; set; }
|
||||
|
||||
public Dictionary<string, string>? Actions { get; set; }
|
||||
}
|
||||
@@ -425,113 +425,3 @@ public class NotificationService
|
||||
return arg?.Replace("\\", "\\\\").Replace("\"", "\\\"") ?? "";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Options for displaying a notification.
|
||||
/// </summary>
|
||||
public class NotificationOptions
|
||||
{
|
||||
public string Title { get; set; } = "";
|
||||
public string Message { get; set; } = "";
|
||||
public string? IconPath { get; set; }
|
||||
public string? IconName { get; set; } // Standard icon name like "dialog-information"
|
||||
public NotificationUrgency Urgency { get; set; } = NotificationUrgency.Normal;
|
||||
public int ExpireTimeMs { get; set; } = 5000; // 5 seconds default
|
||||
public string? Category { get; set; } // e.g., "email", "im", "transfer"
|
||||
public bool IsTransient { get; set; }
|
||||
public Dictionary<string, string>? Actions { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Notification urgency level.
|
||||
/// </summary>
|
||||
public enum NotificationUrgency
|
||||
{
|
||||
Low,
|
||||
Normal,
|
||||
Critical
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reason a notification was closed.
|
||||
/// </summary>
|
||||
public enum NotificationCloseReason
|
||||
{
|
||||
Expired = 1,
|
||||
Dismissed = 2,
|
||||
Closed = 3,
|
||||
Undefined = 4
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal context for tracking active notifications.
|
||||
/// </summary>
|
||||
internal class NotificationContext
|
||||
{
|
||||
public string? Tag { get; set; }
|
||||
public Dictionary<string, Action?>? ActionCallbacks { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event args for notification action events.
|
||||
/// </summary>
|
||||
public class NotificationActionEventArgs : EventArgs
|
||||
{
|
||||
public uint NotificationId { get; }
|
||||
public string ActionKey { get; }
|
||||
public string? Tag { get; }
|
||||
|
||||
public NotificationActionEventArgs(uint notificationId, string actionKey, string? tag)
|
||||
{
|
||||
NotificationId = notificationId;
|
||||
ActionKey = actionKey;
|
||||
Tag = tag;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event args for notification closed events.
|
||||
/// </summary>
|
||||
public class NotificationClosedEventArgs : EventArgs
|
||||
{
|
||||
public uint NotificationId { get; }
|
||||
public NotificationCloseReason Reason { get; }
|
||||
public string? Tag { get; }
|
||||
|
||||
public NotificationClosedEventArgs(uint notificationId, NotificationCloseReason reason, string? tag)
|
||||
{
|
||||
NotificationId = notificationId;
|
||||
Reason = reason;
|
||||
Tag = tag;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines an action button for a notification.
|
||||
/// </summary>
|
||||
public class NotificationAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Internal action key (not displayed).
|
||||
/// </summary>
|
||||
public string Key { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Display label for the action button.
|
||||
/// </summary>
|
||||
public string Label { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Callback to invoke when the action is clicked.
|
||||
/// </summary>
|
||||
public Action? Callback { get; set; }
|
||||
|
||||
public NotificationAction() { }
|
||||
|
||||
public NotificationAction(string key, string label, Action? callback = null)
|
||||
{
|
||||
Key = key;
|
||||
Label = label;
|
||||
Callback = callback;
|
||||
}
|
||||
}
|
||||
|
||||
11
Services/NotificationUrgency.cs
Normal file
11
Services/NotificationUrgency.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum NotificationUrgency
|
||||
{
|
||||
Low,
|
||||
Normal,
|
||||
Critical
|
||||
}
|
||||
41
Services/NullAccessibilityService.cs
Normal file
41
Services/NullAccessibilityService.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class NullAccessibilityService : IAccessibilityService
|
||||
{
|
||||
public bool IsEnabled => false;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
}
|
||||
|
||||
public void Register(IAccessible accessible)
|
||||
{
|
||||
}
|
||||
|
||||
public void Unregister(IAccessible accessible)
|
||||
{
|
||||
}
|
||||
|
||||
public void NotifyFocusChanged(IAccessible? accessible)
|
||||
{
|
||||
}
|
||||
|
||||
public void NotifyPropertyChanged(IAccessible accessible, AccessibleProperty property)
|
||||
{
|
||||
}
|
||||
|
||||
public void NotifyStateChanged(IAccessible accessible, AccessibleState state, bool value)
|
||||
{
|
||||
}
|
||||
|
||||
public void Announce(string text, AnnouncementPriority priority = AnnouncementPriority.Polite)
|
||||
{
|
||||
}
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
}
|
||||
}
|
||||
44
Services/NullInputMethodService.cs
Normal file
44
Services/NullInputMethodService.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class NullInputMethodService : IInputMethodService
|
||||
{
|
||||
public bool IsActive => false;
|
||||
|
||||
public string PreEditText => string.Empty;
|
||||
|
||||
public int PreEditCursorPosition => 0;
|
||||
|
||||
public event EventHandler<TextCommittedEventArgs>? TextCommitted;
|
||||
|
||||
public event EventHandler<PreEditChangedEventArgs>? PreEditChanged;
|
||||
|
||||
public event EventHandler? PreEditEnded;
|
||||
|
||||
public void Initialize(IntPtr windowHandle)
|
||||
{
|
||||
}
|
||||
|
||||
public void SetFocus(IInputContext? context)
|
||||
{
|
||||
}
|
||||
|
||||
public void SetCursorLocation(int x, int y, int width, int height)
|
||||
{
|
||||
}
|
||||
|
||||
public bool ProcessKeyEvent(uint keyCode, KeyModifiers modifiers, bool isKeyDown)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
}
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -363,117 +363,3 @@ public class PortalFilePickerService : IFilePicker
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Folder picker service using xdg-desktop-portal for native dialogs.
|
||||
/// </summary>
|
||||
public class PortalFolderPickerService
|
||||
{
|
||||
public async Task<FolderPickerResult> PickAsync(FolderPickerOptions? options = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
options ??= new FolderPickerOptions();
|
||||
|
||||
// Use zenity/kdialog for folder selection (simpler than portal)
|
||||
string? selectedFolder = null;
|
||||
|
||||
if (IsCommandAvailable("zenity"))
|
||||
{
|
||||
var args = $"--file-selection --directory --title=\"{options.Title ?? "Select Folder"}\"";
|
||||
selectedFolder = await Task.Run(() => RunCommand("zenity", args)?.Trim());
|
||||
}
|
||||
else if (IsCommandAvailable("kdialog"))
|
||||
{
|
||||
var args = $"--getexistingdirectory . --title \"{options.Title ?? "Select Folder"}\"";
|
||||
selectedFolder = await Task.Run(() => RunCommand("kdialog", args)?.Trim());
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(selectedFolder) && Directory.Exists(selectedFolder))
|
||||
{
|
||||
return new FolderPickerResult(new FolderResult(selectedFolder));
|
||||
}
|
||||
|
||||
return new FolderPickerResult(null);
|
||||
}
|
||||
|
||||
public async Task<FolderPickerResult> PickAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await PickAsync(null, cancellationToken);
|
||||
}
|
||||
|
||||
private bool IsCommandAvailable(string command)
|
||||
{
|
||||
try
|
||||
{
|
||||
var output = RunCommand("which", command);
|
||||
return !string.IsNullOrWhiteSpace(output);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private string? RunCommand(string command, string arguments)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var process = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = command,
|
||||
Arguments = arguments,
|
||||
RedirectStandardOutput = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
}
|
||||
};
|
||||
|
||||
process.Start();
|
||||
var output = process.StandardOutput.ReadToEnd();
|
||||
process.WaitForExit(30000);
|
||||
return output;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Result of a folder picker operation.
|
||||
/// </summary>
|
||||
public class FolderResult
|
||||
{
|
||||
public string Path { get; }
|
||||
public string Name => System.IO.Path.GetFileName(Path) ?? Path;
|
||||
|
||||
public FolderResult(string path)
|
||||
{
|
||||
Path = path;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Result wrapper for folder picker.
|
||||
/// </summary>
|
||||
public class FolderPickerResult
|
||||
{
|
||||
public FolderResult? Folder { get; }
|
||||
public bool WasSuccessful => Folder != null;
|
||||
|
||||
public FolderPickerResult(FolderResult? folder)
|
||||
{
|
||||
Folder = folder;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Options for folder picker.
|
||||
/// </summary>
|
||||
public class FolderPickerOptions
|
||||
{
|
||||
public string? Title { get; set; }
|
||||
public string? InitialDirectory { get; set; }
|
||||
}
|
||||
|
||||
77
Services/PortalFolderPickerService.cs
Normal file
77
Services/PortalFolderPickerService.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class PortalFolderPickerService
|
||||
{
|
||||
public async Task<FolderPickerResult> PickAsync(FolderPickerOptions? options = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
options ??= new FolderPickerOptions();
|
||||
|
||||
string? result = null;
|
||||
|
||||
if (IsCommandAvailable("zenity"))
|
||||
{
|
||||
var args = $"--file-selection --directory --title=\"{options.Title ?? "Select Folder"}\"";
|
||||
result = await Task.Run(() => RunCommand("zenity", args)?.Trim(), cancellationToken);
|
||||
}
|
||||
else if (IsCommandAvailable("kdialog"))
|
||||
{
|
||||
var args = $"--getexistingdirectory . --title \"{options.Title ?? "Select Folder"}\"";
|
||||
result = await Task.Run(() => RunCommand("kdialog", args)?.Trim(), cancellationToken);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(result) && Directory.Exists(result))
|
||||
{
|
||||
return new FolderPickerResult(new FolderResult(result));
|
||||
}
|
||||
|
||||
return new FolderPickerResult(null);
|
||||
}
|
||||
|
||||
public async Task<FolderPickerResult> PickAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await PickAsync(null, cancellationToken);
|
||||
}
|
||||
|
||||
private bool IsCommandAvailable(string command)
|
||||
{
|
||||
try
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(RunCommand("which", command));
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private string? RunCommand(string command, string arguments)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var process = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = command,
|
||||
Arguments = arguments,
|
||||
RedirectStandardOutput = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
}
|
||||
};
|
||||
process.Start();
|
||||
var result = process.StandardOutput.ReadToEnd();
|
||||
process.WaitForExit(30000);
|
||||
return result;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
13
Services/PreEditAttribute.cs
Normal file
13
Services/PreEditAttribute.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class PreEditAttribute
|
||||
{
|
||||
public int Start { get; set; }
|
||||
|
||||
public int Length { get; set; }
|
||||
|
||||
public PreEditAttributeType Type { get; set; }
|
||||
}
|
||||
12
Services/PreEditAttributeType.cs
Normal file
12
Services/PreEditAttributeType.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum PreEditAttributeType
|
||||
{
|
||||
None,
|
||||
Underline,
|
||||
Highlighted,
|
||||
Reverse
|
||||
}
|
||||
20
Services/PreEditChangedEventArgs.cs
Normal file
20
Services/PreEditChangedEventArgs.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class PreEditChangedEventArgs : EventArgs
|
||||
{
|
||||
public string PreEditText { get; }
|
||||
|
||||
public int CursorPosition { get; }
|
||||
|
||||
public IReadOnlyList<PreEditAttribute> Attributes { get; }
|
||||
|
||||
public PreEditChangedEventArgs(string preEditText, int cursorPosition, IReadOnlyList<PreEditAttribute>? attributes = null)
|
||||
{
|
||||
PreEditText = preEditText;
|
||||
CursorPosition = cursorPosition;
|
||||
Attributes = attributes ?? Array.Empty<PreEditAttribute>();
|
||||
}
|
||||
}
|
||||
20
Services/ScaleChangedEventArgs.cs
Normal file
20
Services/ScaleChangedEventArgs.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class ScaleChangedEventArgs : EventArgs
|
||||
{
|
||||
public float OldScale { get; }
|
||||
|
||||
public float NewScale { get; }
|
||||
|
||||
public float NewDpi { get; }
|
||||
|
||||
public ScaleChangedEventArgs(float oldScale, float newScale, float newDpi)
|
||||
{
|
||||
OldScale = oldScale;
|
||||
NewScale = newScale;
|
||||
NewDpi = newDpi;
|
||||
}
|
||||
}
|
||||
29
Services/SystemColors.cs
Normal file
29
Services/SystemColors.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class SystemColors
|
||||
{
|
||||
public SKColor Background { get; init; }
|
||||
|
||||
public SKColor Surface { get; init; }
|
||||
|
||||
public SKColor Primary { get; init; }
|
||||
|
||||
public SKColor OnPrimary { get; init; }
|
||||
|
||||
public SKColor Text { get; init; }
|
||||
|
||||
public SKColor TextSecondary { get; init; }
|
||||
|
||||
public SKColor Border { get; init; }
|
||||
|
||||
public SKColor Divider { get; init; }
|
||||
|
||||
public SKColor Error { get; init; }
|
||||
|
||||
public SKColor Success { get; init; }
|
||||
}
|
||||
10
Services/SystemTheme.cs
Normal file
10
Services/SystemTheme.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum SystemTheme
|
||||
{
|
||||
Light,
|
||||
Dark
|
||||
}
|
||||
@@ -425,57 +425,3 @@ public class SystemThemeService
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// System theme (light or dark mode).
|
||||
/// </summary>
|
||||
public enum SystemTheme
|
||||
{
|
||||
Light,
|
||||
Dark
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Detected desktop environment.
|
||||
/// </summary>
|
||||
public enum DesktopEnvironment
|
||||
{
|
||||
Unknown,
|
||||
GNOME,
|
||||
KDE,
|
||||
XFCE,
|
||||
MATE,
|
||||
Cinnamon,
|
||||
LXQt,
|
||||
LXDE
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event args for theme changes.
|
||||
/// </summary>
|
||||
public class ThemeChangedEventArgs : EventArgs
|
||||
{
|
||||
public SystemTheme NewTheme { get; }
|
||||
|
||||
public ThemeChangedEventArgs(SystemTheme newTheme)
|
||||
{
|
||||
NewTheme = newTheme;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// System colors based on the current theme.
|
||||
/// </summary>
|
||||
public class SystemColors
|
||||
{
|
||||
public SKColor Background { get; init; }
|
||||
public SKColor Surface { get; init; }
|
||||
public SKColor Primary { get; init; }
|
||||
public SKColor OnPrimary { get; init; }
|
||||
public SKColor Text { get; init; }
|
||||
public SKColor TextSecondary { get; init; }
|
||||
public SKColor Border { get; init; }
|
||||
public SKColor Divider { get; init; }
|
||||
public SKColor Error { get; init; }
|
||||
public SKColor Success { get; init; }
|
||||
}
|
||||
|
||||
@@ -268,15 +268,3 @@ public class SystemTrayService : IDisposable
|
||||
Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a tray menu item.
|
||||
/// </summary>
|
||||
public class TrayMenuItem
|
||||
{
|
||||
public string Text { get; set; } = "";
|
||||
public Action? Action { get; set; }
|
||||
public bool IsSeparator { get; set; }
|
||||
public bool IsEnabled { get; set; } = true;
|
||||
public string? IconPath { get; set; }
|
||||
}
|
||||
|
||||
14
Services/TextCommittedEventArgs.cs
Normal file
14
Services/TextCommittedEventArgs.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class TextCommittedEventArgs : EventArgs
|
||||
{
|
||||
public string Text { get; }
|
||||
|
||||
public TextCommittedEventArgs(string text)
|
||||
{
|
||||
Text = text;
|
||||
}
|
||||
}
|
||||
22
Services/TextRun.cs
Normal file
22
Services/TextRun.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class TextRun
|
||||
{
|
||||
public string Text { get; }
|
||||
|
||||
public SKTypeface Typeface { get; }
|
||||
|
||||
public int StartIndex { get; }
|
||||
|
||||
public TextRun(string text, SKTypeface typeface, int startIndex)
|
||||
{
|
||||
Text = text;
|
||||
Typeface = typeface;
|
||||
StartIndex = startIndex;
|
||||
}
|
||||
}
|
||||
14
Services/ThemeChangedEventArgs.cs
Normal file
14
Services/ThemeChangedEventArgs.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class ThemeChangedEventArgs : EventArgs
|
||||
{
|
||||
public SystemTheme NewTheme { get; }
|
||||
|
||||
public ThemeChangedEventArgs(SystemTheme newTheme)
|
||||
{
|
||||
NewTheme = newTheme;
|
||||
}
|
||||
}
|
||||
17
Services/TrayMenuItem.cs
Normal file
17
Services/TrayMenuItem.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class TrayMenuItem
|
||||
{
|
||||
public string Text { get; set; } = "";
|
||||
|
||||
public Action? Action { get; set; }
|
||||
|
||||
public bool IsSeparator { get; set; }
|
||||
|
||||
public bool IsEnabled { get; set; } = true;
|
||||
|
||||
public string? IconPath { get; set; }
|
||||
}
|
||||
12
Services/VideoAccelerationApi.cs
Normal file
12
Services/VideoAccelerationApi.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum VideoAccelerationApi
|
||||
{
|
||||
Auto,
|
||||
VaApi,
|
||||
Vdpau,
|
||||
Software
|
||||
}
|
||||
44
Services/VideoFrame.cs
Normal file
44
Services/VideoFrame.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class VideoFrame : IDisposable
|
||||
{
|
||||
private bool _disposed;
|
||||
private Action? _releaseCallback;
|
||||
|
||||
public int Width { get; init; }
|
||||
|
||||
public int Height { get; init; }
|
||||
|
||||
public IntPtr DataY { get; init; }
|
||||
|
||||
public IntPtr DataU { get; init; }
|
||||
|
||||
public IntPtr DataV { get; init; }
|
||||
|
||||
public int StrideY { get; init; }
|
||||
|
||||
public int StrideU { get; init; }
|
||||
|
||||
public int StrideV { get; init; }
|
||||
|
||||
public long Timestamp { get; init; }
|
||||
|
||||
public bool IsKeyFrame { get; init; }
|
||||
|
||||
internal void SetReleaseCallback(Action callback)
|
||||
{
|
||||
_releaseCallback = callback;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
_releaseCallback?.Invoke();
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
17
Services/VideoProfile.cs
Normal file
17
Services/VideoProfile.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public enum VideoProfile
|
||||
{
|
||||
H264Baseline,
|
||||
H264Main,
|
||||
H264High,
|
||||
H265Main,
|
||||
H265Main10,
|
||||
Vp8,
|
||||
Vp9Profile0,
|
||||
Vp9Profile2,
|
||||
Av1Main
|
||||
}
|
||||
73
Services/VirtualizationExtensions.cs
Normal file
73
Services/VirtualizationExtensions.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public static class VirtualizationExtensions
|
||||
{
|
||||
public static (int first, int last) CalculateVisibleRange(float scrollOffset, float viewportHeight, float itemHeight, float itemSpacing, int totalItems)
|
||||
{
|
||||
if (totalItems == 0)
|
||||
{
|
||||
return (-1, -1);
|
||||
}
|
||||
|
||||
var totalItemHeight = itemHeight + itemSpacing;
|
||||
var first = Math.Max(0, (int)(scrollOffset / totalItemHeight));
|
||||
var last = Math.Min(totalItems - 1, (int)((scrollOffset + viewportHeight) / totalItemHeight) + 1);
|
||||
|
||||
return (first, last);
|
||||
}
|
||||
|
||||
public static (int first, int last) CalculateVisibleRangeVariable(float scrollOffset, float viewportHeight, Func<int, float> getItemHeight, float itemSpacing, int totalItems)
|
||||
{
|
||||
if (totalItems == 0)
|
||||
{
|
||||
return (-1, -1);
|
||||
}
|
||||
|
||||
var firstVisible = 0;
|
||||
var currentOffset = 0f;
|
||||
|
||||
for (var i = 0; i < totalItems; i++)
|
||||
{
|
||||
var height = getItemHeight(i);
|
||||
if (currentOffset + height > scrollOffset)
|
||||
{
|
||||
firstVisible = i;
|
||||
break;
|
||||
}
|
||||
currentOffset += height + itemSpacing;
|
||||
}
|
||||
|
||||
var lastVisible = firstVisible;
|
||||
var endOffset = scrollOffset + viewportHeight;
|
||||
|
||||
for (var i = firstVisible; i < totalItems; i++)
|
||||
{
|
||||
var height = getItemHeight(i);
|
||||
if (currentOffset > endOffset)
|
||||
{
|
||||
break;
|
||||
}
|
||||
lastVisible = i;
|
||||
currentOffset += height + itemSpacing;
|
||||
}
|
||||
|
||||
return (firstVisible, lastVisible);
|
||||
}
|
||||
|
||||
public static (int firstRow, int lastRow) CalculateVisibleGridRange(float scrollOffset, float viewportHeight, float rowHeight, float rowSpacing, int totalRows)
|
||||
{
|
||||
if (totalRows == 0)
|
||||
{
|
||||
return (-1, -1);
|
||||
}
|
||||
|
||||
var totalRowHeight = rowHeight + rowSpacing;
|
||||
var firstRow = Math.Max(0, (int)(scrollOffset / totalRowHeight));
|
||||
var lastRow = Math.Min(totalRows - 1, (int)((scrollOffset + viewportHeight) / totalRowHeight) + 1);
|
||||
|
||||
return (firstRow, lastRow);
|
||||
}
|
||||
}
|
||||
@@ -202,106 +202,3 @@ public class VirtualizationManager<T> where T : SkiaView
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for virtualization.
|
||||
/// </summary>
|
||||
public static class VirtualizationExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Calculates visible item range for a vertical list.
|
||||
/// </summary>
|
||||
/// <param name="scrollOffset">Current scroll offset.</param>
|
||||
/// <param name="viewportHeight">Height of visible area.</param>
|
||||
/// <param name="itemHeight">Height of each item (fixed).</param>
|
||||
/// <param name="itemSpacing">Spacing between items.</param>
|
||||
/// <param name="totalItems">Total number of items.</param>
|
||||
/// <returns>Tuple of (firstVisible, lastVisible) indices.</returns>
|
||||
public static (int first, int last) CalculateVisibleRange(
|
||||
float scrollOffset,
|
||||
float viewportHeight,
|
||||
float itemHeight,
|
||||
float itemSpacing,
|
||||
int totalItems)
|
||||
{
|
||||
if (totalItems == 0)
|
||||
return (-1, -1);
|
||||
|
||||
var rowHeight = itemHeight + itemSpacing;
|
||||
var first = Math.Max(0, (int)(scrollOffset / rowHeight));
|
||||
var last = Math.Min(totalItems - 1, (int)((scrollOffset + viewportHeight) / rowHeight) + 1);
|
||||
|
||||
return (first, last);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates visible item range for variable height items.
|
||||
/// </summary>
|
||||
/// <param name="scrollOffset">Current scroll offset.</param>
|
||||
/// <param name="viewportHeight">Height of visible area.</param>
|
||||
/// <param name="getItemHeight">Function to get height of item at index.</param>
|
||||
/// <param name="itemSpacing">Spacing between items.</param>
|
||||
/// <param name="totalItems">Total number of items.</param>
|
||||
/// <returns>Tuple of (firstVisible, lastVisible) indices.</returns>
|
||||
public static (int first, int last) CalculateVisibleRangeVariable(
|
||||
float scrollOffset,
|
||||
float viewportHeight,
|
||||
Func<int, float> getItemHeight,
|
||||
float itemSpacing,
|
||||
int totalItems)
|
||||
{
|
||||
if (totalItems == 0)
|
||||
return (-1, -1);
|
||||
|
||||
int first = 0;
|
||||
float cumulativeHeight = 0;
|
||||
|
||||
// Find first visible
|
||||
for (int i = 0; i < totalItems; i++)
|
||||
{
|
||||
var itemHeight = getItemHeight(i);
|
||||
if (cumulativeHeight + itemHeight > scrollOffset)
|
||||
{
|
||||
first = i;
|
||||
break;
|
||||
}
|
||||
cumulativeHeight += itemHeight + itemSpacing;
|
||||
}
|
||||
|
||||
// Find last visible
|
||||
int last = first;
|
||||
var endOffset = scrollOffset + viewportHeight;
|
||||
for (int i = first; i < totalItems; i++)
|
||||
{
|
||||
var itemHeight = getItemHeight(i);
|
||||
if (cumulativeHeight > endOffset)
|
||||
{
|
||||
break;
|
||||
}
|
||||
last = i;
|
||||
cumulativeHeight += itemHeight + itemSpacing;
|
||||
}
|
||||
|
||||
return (first, last);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates visible item range for a grid layout.
|
||||
/// </summary>
|
||||
public static (int firstRow, int lastRow) CalculateVisibleGridRange(
|
||||
float scrollOffset,
|
||||
float viewportHeight,
|
||||
float rowHeight,
|
||||
float rowSpacing,
|
||||
int totalRows)
|
||||
{
|
||||
if (totalRows == 0)
|
||||
return (-1, -1);
|
||||
|
||||
var effectiveRowHeight = rowHeight + rowSpacing;
|
||||
var first = Math.Max(0, (int)(scrollOffset / effectiveRowHeight));
|
||||
var last = Math.Min(totalRows - 1, (int)((scrollOffset + viewportHeight) / effectiveRowHeight) + 1);
|
||||
|
||||
return (first, last);
|
||||
}
|
||||
}
|
||||
|
||||
63
Services/WaylandDisplayWindow.cs
Normal file
63
Services/WaylandDisplayWindow.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using Microsoft.Maui.Platform.Linux.Window;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class WaylandDisplayWindow : IDisplayWindow, IDisposable
|
||||
{
|
||||
private readonly WaylandWindow _window;
|
||||
|
||||
public int Width => _window.Width;
|
||||
|
||||
public int Height => _window.Height;
|
||||
|
||||
public bool IsRunning => _window.IsRunning;
|
||||
|
||||
public IntPtr PixelData => _window.PixelData;
|
||||
|
||||
public int Stride => _window.Stride;
|
||||
|
||||
public event EventHandler<KeyEventArgs>? KeyDown;
|
||||
public event EventHandler<KeyEventArgs>? KeyUp;
|
||||
public event EventHandler<TextInputEventArgs>? TextInput;
|
||||
public event EventHandler<PointerEventArgs>? PointerMoved;
|
||||
public event EventHandler<PointerEventArgs>? PointerPressed;
|
||||
public event EventHandler<PointerEventArgs>? PointerReleased;
|
||||
public event EventHandler<ScrollEventArgs>? Scroll;
|
||||
public event EventHandler? Exposed;
|
||||
public event EventHandler<(int Width, int Height)>? Resized;
|
||||
public event EventHandler? CloseRequested;
|
||||
|
||||
public WaylandDisplayWindow(string title, int width, int height)
|
||||
{
|
||||
_window = new WaylandWindow(title, width, height);
|
||||
_window.KeyDown += (s, e) => KeyDown?.Invoke(this, e);
|
||||
_window.KeyUp += (s, e) => KeyUp?.Invoke(this, e);
|
||||
_window.TextInput += (s, e) => TextInput?.Invoke(this, e);
|
||||
_window.PointerMoved += (s, e) => PointerMoved?.Invoke(this, e);
|
||||
_window.PointerPressed += (s, e) => PointerPressed?.Invoke(this, e);
|
||||
_window.PointerReleased += (s, e) => PointerReleased?.Invoke(this, e);
|
||||
_window.Scroll += (s, e) => Scroll?.Invoke(this, e);
|
||||
_window.Exposed += (s, e) => Exposed?.Invoke(this, e);
|
||||
_window.Resized += (s, e) => Resized?.Invoke(this, e);
|
||||
_window.CloseRequested += (s, e) => CloseRequested?.Invoke(this, e);
|
||||
}
|
||||
|
||||
public void Show() => _window.Show();
|
||||
|
||||
public void Hide() => _window.Hide();
|
||||
|
||||
public void SetTitle(string title) => _window.SetTitle(title);
|
||||
|
||||
public void Resize(int width, int height) => _window.Resize(width, height);
|
||||
|
||||
public void ProcessEvents() => _window.ProcessEvents();
|
||||
|
||||
public void Stop() => _window.Stop();
|
||||
|
||||
public void CommitFrame() => _window.CommitFrame();
|
||||
|
||||
public void Dispose() => _window.Dispose();
|
||||
}
|
||||
57
Services/X11DisplayWindow.cs
Normal file
57
Services/X11DisplayWindow.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using Microsoft.Maui.Platform.Linux.Window;
|
||||
|
||||
namespace Microsoft.Maui.Platform.Linux.Services;
|
||||
|
||||
public class X11DisplayWindow : IDisplayWindow, IDisposable
|
||||
{
|
||||
private readonly X11Window _window;
|
||||
|
||||
public int Width => _window.Width;
|
||||
|
||||
public int Height => _window.Height;
|
||||
|
||||
public bool IsRunning => _window.IsRunning;
|
||||
|
||||
public event EventHandler<KeyEventArgs>? KeyDown;
|
||||
public event EventHandler<KeyEventArgs>? KeyUp;
|
||||
public event EventHandler<TextInputEventArgs>? TextInput;
|
||||
public event EventHandler<PointerEventArgs>? PointerMoved;
|
||||
public event EventHandler<PointerEventArgs>? PointerPressed;
|
||||
public event EventHandler<PointerEventArgs>? PointerReleased;
|
||||
public event EventHandler<ScrollEventArgs>? Scroll;
|
||||
public event EventHandler? Exposed;
|
||||
public event EventHandler<(int Width, int Height)>? Resized;
|
||||
public event EventHandler? CloseRequested;
|
||||
|
||||
public X11DisplayWindow(string title, int width, int height)
|
||||
{
|
||||
_window = new X11Window(title, width, height);
|
||||
_window.KeyDown += (s, e) => KeyDown?.Invoke(this, e);
|
||||
_window.KeyUp += (s, e) => KeyUp?.Invoke(this, e);
|
||||
_window.TextInput += (s, e) => TextInput?.Invoke(this, e);
|
||||
_window.PointerMoved += (s, e) => PointerMoved?.Invoke(this, e);
|
||||
_window.PointerPressed += (s, e) => PointerPressed?.Invoke(this, e);
|
||||
_window.PointerReleased += (s, e) => PointerReleased?.Invoke(this, e);
|
||||
_window.Scroll += (s, e) => Scroll?.Invoke(this, e);
|
||||
_window.Exposed += (s, e) => Exposed?.Invoke(this, e);
|
||||
_window.Resized += (s, e) => Resized?.Invoke(this, e);
|
||||
_window.CloseRequested += (s, e) => CloseRequested?.Invoke(this, e);
|
||||
}
|
||||
|
||||
public void Show() => _window.Show();
|
||||
|
||||
public void Hide() => _window.Hide();
|
||||
|
||||
public void SetTitle(string title) => _window.SetTitle(title);
|
||||
|
||||
public void Resize(int width, int height) => _window.Resize(width, height);
|
||||
|
||||
public void ProcessEvents() => _window.ProcessEvents();
|
||||
|
||||
public void Stop() => _window.Stop();
|
||||
|
||||
public void Dispose() => _window.Dispose();
|
||||
}
|
||||
Reference in New Issue
Block a user