### Basic Setup with DrawnUI in C# and XAML Source: https://github.com/taublast/drawnui/blob/main/aidocs/00-master-index.md Demonstrates the basic setup for DrawnUI by configuring the MauiProgram and initializing the Canvas control in XAML. This pattern is essential for getting started with DrawnUI applications. ```csharp // MauiProgram.cs builder.UseDrawnUi(new() { MobileIsFullscreen = true }); ``` ```xml ``` -------------------------------- ### Advanced Fluent API Patterns for SkiaButton Source: https://github.com/taublast/drawnui/blob/main/aidocs/03-skiabutton-interactive-controls.md Demonstrates advanced fluent API patterns for configuring SkiaButton, including event handling, styling, and layout integration. This example shows how to chain methods for a more readable and concise button setup. ```csharp ```csharp // Real-world example from AppoMobi.Mobile project SkiaButton actionButton; var layout = new SkiaLayout() { Type = LayoutType.Column, Spacing = 16, Children = new List { new SkiaButton("Save Changes") { BackgroundColor = Colors.Blue, TextColor = Colors.White, CornerRadius = 8 } .Assign(out actionButton) .OnTapped(async btn => { btn.IsEnabled = false; btn.Text = "Saving..."; try { await SaveChangesAsync(); btn.Text = "Saved!"; await Task.Delay(1000); btn.Text = "Save Changes"; } finally { btn.IsEnabled = true; } }) .WithCache(SkiaCacheType.Operations) .Height(44) .CenterX(), new SkiaButton("Cancel") .OnTapped(btn => Navigation.PopAsync()) .Adapt(btn => { if (HasUnsavedChanges) { btn.BackgroundColor = Colors.Orange; btn.Text = "Discard Changes"; } }) } } .Initialize(layout => { // Access assigned variables after construction actionButton.CommandTapped = new Command(() => { // Alternative command binding }); }); ``` ``` -------------------------------- ### Fluent Method Examples (C#) Source: https://github.com/taublast/drawnui/blob/main/docs/articles/first-app-code.md This section provides examples of key fluent methods used in the project, including `.Assign()`, `.OnTapped()`, and `.ObserveProperties()`. It also shows how to use constructor parameters for setting text content, promoting cleaner and more readable code. ```csharp new SkiaButton("Click Me!").Assign(out btnClickMe) ``` ```csharp button.OnTapped(async me => { // Handle tap with direct access to the control }) ``` ```csharp label.ObserveProperties(() => btnClickMe, [nameof(SkiaButton.Text)], me => { /* Update logic */ }) ``` ```csharp new SkiaLabel("Text content") // Direct text in constructor new SkiaButton("Button text") // Cleaner than setting Text property ``` -------------------------------- ### AI Agent Quick Start with SkiaCamera Source: https://github.com/taublast/drawnui/blob/main/src/Maui/Addons/DrawnUi.Maui.Camera/README.md Provides a quick start guide for AI agents integrating with SkiaCamera, demonstrating setup, dual-channel processing, and manual camera selection. ```csharp // 1. Setup dual-channel camera var camera = new SkiaCamera { Facing = CameraPosition.Default, PhotoQuality = CaptureQuality.Medium, IsOn = true }; // 2. CHANNEL 1: Live preview processing for AI/ML camera.NewPreviewSet += (s, source) => { // Real-time AI processing on preview frames Task.Run(() => ProcessFrameForAI(source.Image)); }; // 3. CHANNEL 2: Captured photo processing camera.CaptureSuccess += (s, captured) => { // High-quality processing on captured photo ProcessCapturedPhoto(captured.Image, captured.Metadata); }; // 4. Manual camera selection var cameras = await camera.GetAvailableCamerasAsync(); camera.Facing = CameraPosition.Manual; camera.CameraIndex = 2; // Select third camera // 5. Take photo (triggers Channel 2 processing) await camera.TakePicture(); ``` -------------------------------- ### Use DrawnUiBasePage for Keyboard Support (XAML) Source: https://github.com/taublast/drawnui/blob/main/docs/_site/articles/getting-started.html This XAML example shows how to use DrawnUiBasePage, which provides built-in keyboard support, for integrating the DrawnUi Canvas. It configures rendering mode and gesture handling. ```xml ``` -------------------------------- ### Initialization and Observation Methods Source: https://github.com/taublast/drawnui/blob/main/docs/_site/api/DrawnUi.Draw.LottieRefreshIndicator.html Methods for initializing UI elements and observing property changes. ```APIDOC ## Initialize ### Description Initializes a UI element with a configuration action. ### Method `Initialize(T element, Action configure)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) Returns the initialized element. #### Response Example None ## ObserveBindingContextOn ### Description Observes changes to the binding context of a target element, triggering an action with source and property name. ### Method `ObserveBindingContextOn(T element, TTarget target, Action action, bool observeChild }}= ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) Returns the element with binding context observation set up. #### Response Example None ## ObserveBindingContext ### Description Observes changes to the binding context of a target element, triggering an action with source and property name. ### Method `ObserveBindingContext(T element, Action action, bool observeChild }}= ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) Returns the element with binding context observation set up. #### Response Example None ## ObserveOn ### Description Observes a specific property on a parent element and triggers an action when it changes, optionally observing child properties. ### Method `ObserveOn(T element, TParent parent, Func targetProperty, string targetPropertyName, Action action, string[] childPropertyNames)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) Returns the element with the specified property observation set up. #### Response Example None ## ObservePropertiesOn ### Description Observes multiple properties on a parent element and triggers an action when any of them change. ### Method `ObservePropertiesOn(T element, TParent parent, Func targetProperty, string targetPropertyName, IEnumerable propertyNames, Action action)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) Returns the element with multiple property observations set up. #### Response Example None ## ObserveProperties ### Description Observes multiple properties on a source object and triggers an action when any of them change. ### Method `ObserveProperties(T element, Func sourceProperty, IEnumerable propertyNames, Action action)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) Returns the element with multiple property observations set up. #### Response Example None ## ObserveProperties (Source Object) ### Description Observes multiple properties on a source object and triggers an action when any of them change. ### Method `ObserveProperties(T element, TSource source, IEnumerable propertyNames, Action action)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) Returns the element with multiple property observations set up. #### Response Example None ## ObservePropertyOn ### Description Observes a specific property on a parent element and triggers an action when it changes. ### Method `ObservePropertyOn(T element, TParent parent, Func targetProperty, string targetPropertyName, string propertyName, Action action)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) Returns the element with the specified property observation set up. #### Response Example None ## ObserveProperty ### Description Observes a specific property on a source object and triggers an action when it changes. ### Method `ObserveProperty(T element, Func sourceProperty, string propertyName, Action action)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) Returns the element with the specified property observation set up. #### Response Example None ## ObserveProperty (Source Object) ### Description Observes a specific property on a source object and triggers an action when it changes. ### Method `ObserveProperty(T element, TSource source, string propertyName, Action action)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) Returns the element with the specified property observation set up. #### Response Example None ## ObserveSelf ### Description Observes changes to the element itself and triggers an action with the element and property name. ### Method `ObserveSelf(T element, Action action)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) Returns the element with self-observation set up. #### Response Example None ## Observe ### Description Observes changes to properties on a source object, triggering an action with the element and property names. ### Method `Observe(T element, Func sourceProperty, Action action, string[] propertyNames)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) Returns the element with property observation set up. #### Response Example None ## Observe (Action with Element) ### Description Observes changes to properties on a source object, triggering an action with only the element. ### Method `Observe(T element, Func sourceProperty, Action action, string[] propertyNames)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) Returns the element with property observation set up. #### Response Example None ## Observe (Source Object) ### Description Observes changes to properties on a source object, triggering an action with the element and property names. ### Method `Observe(T element, TSource source, Action action, string[] propertyNames)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) Returns the element with property observation set up. #### Response Example None ``` -------------------------------- ### Display an SVG Icon using DrawnUi Canvas Source: https://github.com/taublast/drawnui/blob/main/docs/_site/articles/getting-started.html Provides a simple example of embedding an SVG icon within a DrawnUi `Canvas` control. It demonstrates the use of `SkiaSvg` with properties like `Source`, `LockRatio`, `TintColor`, and `WidthRequest` for sizing and appearance. ```xaml ``` -------------------------------- ### SkiaImage C# Examples Source: https://context7.com/taublast/drawnui/llms.txt Provides C# examples for SkiaImage, including programmatic creation with source, loading options, and event handling for success and error. It also demonstrates a custom `BannerImage` class inheriting from SkiaImage to implement a fade-in animation on successful image load. ```csharp // Programmatic image with loading events var urlImage = new SkiaImage { Source = "https://example.com/image.jpg", LoadSourceOnFirstDraw = true, Aspect = TransformAspect.AspectCover, WidthRequest = 200, HeightRequest = 200, UseCache = SkiaCacheType.Image }; urlImage.Success += (s, e) => Console.WriteLine("Image loaded successfully!"); urlImage.Error += (s, e) => Console.WriteLine("Failed to load image"); // Custom fade-in animation on load public class BannerImage : SkiaImage { public override void OnSuccess(string source) { base.OnSuccess(source); this.Opacity = 0.01; _ = this.FadeToAsync(1, 300, Easing.SinIn); } } ``` -------------------------------- ### Configure .NET MAUI Project for DrawnUI Source: https://github.com/taublast/drawnui/blob/main/docs/_site/articles/getting-started.html Specifies the minimum supported OS versions for various platforms and includes necessary MAUI and DrawnUI NuGet packages. This setup ensures compatibility and access to DrawnUI features within your .NET MAUI application. ```xml 15.0 15.2 21.0 10.0.19041.0 10.0.19041.0 ``` -------------------------------- ### Create New MAUI Project - Bash Source: https://github.com/taublast/drawnui/blob/main/docs/articles/interactive-cards.md This snippet demonstrates how to create a new MAUI project named 'InteractiveCardsTutorial' and navigate into its directory using the .NET CLI. ```bash dotnet new maui -n InteractiveCardsTutorial cd InteractiveCardsTutorial ``` -------------------------------- ### SkiaButton C# Fluent API Example Source: https://context7.com/taublast/drawnui/llms.txt Shows how to create and configure a SkiaButton programmatically using a fluent API in C#. This example includes setting text, appearance, handling tap events with asynchronous operations, and chaining method calls for layout. ```csharp // Fluent API for programmatic button creation SkiaButton actionButton; var button = new SkiaButton("Save Changes") { BackgroundColor = Colors.Blue, TextColor = Colors.White, CornerRadius = 8 } .Assign(out actionButton) .OnTapped(async btn => { btn.IsEnabled = false; btn.Text = "Saving..."; try { await SaveChangesAsync(); btn.Text = "Saved!"; await Task.Delay(1000); btn.Text = "Save Changes"; } finally { btn.IsEnabled = true; } }) .Height(44) .CenterX(); ``` -------------------------------- ### Create Linear Gradient Programmatically in C# Source: https://github.com/taublast/drawnui/blob/main/docs/_site/articles/advanced/gradients.html This C# code example demonstrates how to create a `SkiaGradient` object programmatically. It sets the gradient type, start and end colors, and start and end points, and then applies it to a control's `FillGradient` property. ```C# var gradient = new SkiaGradient { Type = SkiaGradientType.Linear, StartColor = Colors.Red, EndColor = Colors.Yellow, StartPoint = new Point(0, 0), EndPoint = new Point(1, 1) }; control.FillGradient = gradient; ``` -------------------------------- ### Observe Multiple Properties in Real-world Example Source: https://github.com/taublast/drawnui/blob/main/docs/_site/articles/fluent-extensions.html A comprehensive example demonstrating the observation of multiple properties on a SkiaButton and updating a SkiaRichLabel based on those changes. It includes observing the button's Text and IsPressed properties to reflect its state in a separate label. ```csharp SkiaButton btnClickMe; ``` -------------------------------- ### Configure DrawnUI Startup Settings in C# Source: https://github.com/taublast/drawnui/blob/main/docs/articles/startup-settings.md Demonstrates how to initialize DrawnUI with custom startup settings in a MAUI application. This includes setting desktop window dimensions, providing a custom logger, enabling desktop keyboard handling, and configuring mobile fullscreen behavior. The Startup delegate allows for post-initialization actions. ```csharp using DrawnUi.Draw; var builder = MauiApp.CreateBuilder(); builder .UseMauiApp() .UseDrawnUi(new DrawnUiStartupSettings { // Desktop window sizing (desktop platforms) DesktopWindow = new() { Width = 375, Height = 800, IsFixedSize = false }, // Provide an ILogger used by Super.Log Logger = LoggerFactory.Create(b => { b.AddConsole(); b.SetMinimumLevel(LogLevel.Information); }).CreateLogger("DrawnUi"), // Optional features UseDesktopKeyboard = true, MobileIsFullscreen = false, // Optional post-initialization hook Startup = services => { // Run custom code once DrawnUI is initialized } }); ``` -------------------------------- ### Complete Shell Application Example (C# Code-Behind) Source: https://github.com/taublast/drawnui/blob/main/docs/articles/controls/shell.md Provides the C# code-behind for the MainShell XAML file, initializing the SkiaShell, registering navigation routes for different pages, and handling tab button taps to navigate between them. It also implements the OnBackButtonPressed method to allow the shell to manage the back navigation. ```csharp public partial class MainShell : DrawnUiBasePage { public SkiaShell Shell { get; private set; } public MainShell() { InitializeComponent(); // Initialize shell Shell = new SkiaShell(); Shell.Initialize(MainCanvas); // Register routes Shell.RegisterRoute("home", typeof(HomePage)); Shell.RegisterRoute("profile", typeof(ProfilePage)); Shell.RegisterRoute("settings", typeof(SettingsPage)); Shell.RegisterRoute("details", typeof(DetailsPage)); // Navigate to initial route Shell.GoToAsync("home"); } private void OnHomeTabTapped(object sender, EventArgs e) { Shell.GoToAsync("home"); } private void OnProfileTabTapped(object sender, EventArgs e) { Shell.GoToAsync("profile"); } private void OnSettingsTabTapped(object sender, EventArgs e) { Shell.GoToAsync("settings"); } protected override bool OnBackButtonPressed() { // Let shell handle back button return Shell.GoBack(true); } } ``` -------------------------------- ### Observe Single Property Change in Real-world Example Source: https://github.com/taublast/drawnui/blob/main/docs/_site/articles/fluent-extensions.html A practical example of using ObserveProperty within a SkiaRichLabel to update its Text property whenever the Text property of the parent (this) changes. This is useful for dynamic UI updates based on internal state. ```csharp new SkiaRichLabel() { Text = this.Text, UseCache = SkiaCacheType.Operations, HorizontalTextAlignment = DrawTextAlignment.Center, VerticalOptions = LayoutOptions.Center, FontSize = 16, FontAttributes = FontAttributes.Bold, TextColor = Colors.White, } .ObserveProperty(this, nameof(Text), me => { me.Text = this.Text; }) ``` -------------------------------- ### Get All Elements Including Self and Parents Source: https://github.com/taublast/drawnui/blob/main/docs/_site/api/DrawnUi.Controls.ScrollPickerLabelLayout.html Collects all elements in the visual tree starting from a VisualElement, including itself and all its ancestors. Useful for context-aware operations. ```csharp public static IEnumerable GetAllWithMyselfParents(VisualElement element) ``` -------------------------------- ### Install and Build Documentation with NPM Source: https://github.com/taublast/drawnui/blob/main/docs/_site/README.html Installs the docfx-flavored-markdown NPM package and builds the documentation. This is an alternative method for environments where .NET is not available. ```bash npm install -g @tsgkadot/docfx-flavored-markdown dfm build ``` -------------------------------- ### Prepend Buffered Data to Output File Source: https://github.com/taublast/drawnui/blob/main/ARCHITECTURE_DIAGRAM.md This process describes how buffered frames (e.g., 5 seconds of pre-recorded video) are prepended to a newly started recording. It involves extracting buffered data, initializing a file encoder, and then writing the buffered frames followed by the live-recorded frames to the output file. The total time for writing to the output file is less than 10ms. ```C# public class RecordingManager { private Queue _preRecordingBuffer = new Queue(); private bool _isPreRecording = true; private bool _isRecordingVideo = false; private Encoder _fileEncoder; public void StartRecording() { _isPreRecording = false; _isRecordingVideo = true; // Step 1: Extract Buffered Data byte[] bufferedData = ExtractBufferedData(); // Step 2: Initialize File Encoder _fileEncoder = new Encoder(); _fileEncoder.Initialize(new EncoderSettings { Bitrate = 8000000, Resolution = new Resolution(1920, 1080) }); // Step 3: Write to Output File // 1. Write buffered frames first (prepend) WriteBufferedFrames(bufferedData); // 2. Then write live recorded frames (handled by encoder during recording) // ... live recording logic ... } private byte[] ExtractBufferedData() { // Simulate extracting data from the pre-recording buffer // In a real scenario, this would aggregate data from _preRecordingBuffer long totalSize = 0; foreach (var frame in _preRecordingBuffer) { totalSize += frame.Data.Length; } byte[] combinedData = new byte[totalSize]; int offset = 0; foreach (var frame in _preRecordingBuffer) { Buffer.BlockCopy(frame.Data, 0, combinedData, offset, frame.Data.Length); offset += frame.Data.Length; } _preRecordingBuffer.Clear(); return combinedData; } private void WriteBufferedFrames(byte[] data) { // Simulate writing the extracted buffered data to the file encoder // This would involve passing the data to the encoder's write function // _fileEncoder.Write(data); Console.WriteLine($"Prepended {data.Length} bytes of buffered data."); } // Placeholder for Encoder class and related types public class Encoder { public void Initialize(EncoderSettings settings) { Console.WriteLine("Encoder Initialized."); } public void Write(byte[] data) { Console.WriteLine("Writing data to file."); } } public class EncoderSettings { public int Bitrate { get; set; } public Resolution Resolution { get; set; } } public struct Resolution { public int Width { get; } public int Height { get; } public Resolution(int width, int height) { Width = width; Height = height; } } } ``` -------------------------------- ### Get Spring Animation Initial Velocity in C# Source: https://github.com/taublast/drawnui/blob/main/docs/_site/api/DrawnUi.Draw.SpringTimingParameters.html Retrieves the initial velocity of the spring animation. This value determines how fast the spring starts its movement. ```csharp public float InitialVelocity { get; } ``` -------------------------------- ### SkiaSlider Range Example (XML) Source: https://github.com/taublast/drawnui/blob/main/docs/controls/range-controls.md Illustrates how to configure a SkiaSlider for range selection by enabling the 'EnableRange' property and setting both 'Start' and 'End' values. ```xml ``` -------------------------------- ### Build and Serve Documentation with DocFX Source: https://github.com/taublast/drawnui/blob/main/docs/_site/README.html Commands to navigate to the docs folder and build the documentation using DocFX. After building, 'docfx serve _site' can be used to preview the generated documentation locally. ```bash cd docs docfx build docfx serve _site ``` -------------------------------- ### Calculate Video Buffer Size (C#) Source: https://github.com/taublast/drawnui/blob/main/src/Maui/Addons/DrawnUi.Maui.Camera/PreRecordingTech.md Provides the formula and an example for calculating the video buffer size based on expected bytes per second, duration, and a safety margin. It also shows the initialization of two byte arrays (_bufferA and _bufferB) for video buffering and a CircularAudioBuffer for audio samples. This calculation is crucial for managing memory efficiently during recording. ```csharp // Video buffer formula: // bufferSize = expectedBytesPerSecond × duration × safetyMargin // Example for 1080p @ 30fps: // - H.264 bitrate: ~15 Mbps = 1.875 MB/s // - 5 seconds: 1.875 × 5 = 9.375 MB // - Safety margin: 1.44x (for IDR frame spikes) // - Total: 13.5 MB per buffer const int bufferSize = (int)(11.25 * 1024 * 1024 * 1.2); // ~13.5 MB _bufferA = new byte[bufferSize]; _bufferB = new byte[bufferSize]; // Audio buffer: // - Circular mode with PreRecordDuration _audioBuffer = new CircularAudioBuffer(PreRecordDuration); ``` -------------------------------- ### Get All Elements Including Parents in C# Source: https://github.com/taublast/drawnui/blob/main/docs/_site/api/DrawnUi.Draw.ContentLayout.html Fetches all elements in the visual tree, starting from the specified element and including its parents. This is helpful for context-aware operations. ```csharp public static IEnumerable GetAllWithMyselfParents(VisualElement element) { // Implementation details... var parents = new List(); parents.Add(element); return parents; } ``` -------------------------------- ### Get All Elements Including Parents Source: https://github.com/taublast/drawnui/blob/main/docs/_site/api/DrawnUi.Controls.SkiaShell.PopupWrapper.html Fetches all elements in the visual tree, starting from a VisualElement and including all its ancestors up to the root. This can be used for traversal or applying properties recursively. ```csharp StaticResourcesExtensions.GetAllWithMyselfParents(VisualElement) ``` -------------------------------- ### Initialize DrawnUI in MauiProgram.cs Source: https://github.com/taublast/drawnui/blob/main/docs/_site/articles/interactive-cards.html This C# code snippet shows how to configure the DrawnUI library within the `MauiProgram.cs` file. It enables desktop keyboard support and sets custom dimensions for the desktop window. Dependencies include the DrawnUi NuGet package. ```csharp using DrawnUi.Infrastructure; public static class MauiProgram { public static MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder(); builder .UseMauiApp() .UseDrawnUi(new DrawnUiStartupSettings { UseDesktopKeyboard = true, DesktopWindow = new() { Width = 400, Height = 700 } }) .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "FontText"); fonts.AddFont("OpenSans-Semibold.ttf", "FontSemibold"); }); return builder.Build(); } } ``` -------------------------------- ### Get All Parents Including Self with StaticResourcesExtensions Source: https://github.com/taublast/drawnui/blob/main/docs/_site/api/DrawnUi.Draw.SkiaHoverMask.html Retrieves a collection of all parent elements, including the element itself, starting from a VisualElement. Useful for traversing the visual tree upwards. ```csharp public static IEnumerable GetAllWithMyselfParents(this VisualElement element) { // Implementation details omitted for brevity return Enumerable.Empty(); } ``` -------------------------------- ### Metal Resource Management: Shared Device and Command Queue (C#) Source: https://github.com/taublast/drawnui/blob/main/src/Maui/Addons/DrawnUi.Maui.Camera/PreRecordingTech.md Explains the best practice of creating and reusing Metal device and command queue resources for the lifetime of the application. This static approach within AppleVideoToolboxEncoder minimizes overhead by avoiding repeated creation and disposal of these core Metal objects. ```csharp // In AppleVideoToolboxEncoder - STATIC shared resources private static IMTLDevice _sharedMetalDevice; private static IMTLCommandQueue _sharedCommandQueue; private static GCHandle _sharedQueuePin; private static readonly object _sharedMetalLock = new(); private void EnsureMetalContext() { lock (_sharedMetalLock) { if (_sharedMetalDevice == null) { _sharedMetalDevice = MTLDevice.SystemDefault; if (_sharedMetalDevice != null) { _sharedCommandQueue = _sharedMetalDevice.CreateCommandQueue(); _sharedQueuePin = GCHandle.Alloc(_sharedCommandQueue, GCHandleType.Pinned); } } } // Per-instance GRContext using shared device/queue if (_encodingContext == null && _sharedMetalDevice != null) { var backend = new GRMtlBackendContext { Device = _sharedMetalDevice, Queue = _sharedCommandQueue }; _encodingContext = GRContext.CreateMetal(backend); _metalCache = new CVMetalTextureCache(_sharedMetalDevice); } } // NOTE: _sharedMetalDevice, _sharedCommandQueue, _sharedQueuePin are NEVER disposed // They are reused across all encoder instances for the app lifetime ``` -------------------------------- ### Professional Shader Camera Setup (C#) Source: https://github.com/taublast/drawnui/blob/main/src/Maui/Addons/DrawnUi.Maui.Camera/README.md Shows how to initialize and configure a CameraWithEffects instance for advanced shader-based camera effects. It enables constant updates for smooth effects, utilizes GPU caching, applies a custom shader, and turns the camera on. ```csharp var camera = new CameraWithEffects { Facing = CameraPosition.Default, ConstantUpdate = true, // For smooth shader effects UseCache = SkiaCacheType.GPU }; // Apply professional look camera.SetCustomShader("Shaders/Camera/action.sksl"); camera.IsOn = true; ``` -------------------------------- ### AnimatedFramesRenderer DefaultFrame Property Source: https://github.com/taublast/drawnui/blob/main/docs/_site/api/DrawnUi.Controls.AnimatedFramesRenderer.html Gets or sets the default frame to display when the animation starts or resets. A value of -1 indicates the last frame. This property is bound to the DefaultFrameProperty. ```csharp public int DefaultFrame { get; set; } ``` -------------------------------- ### SkiaButton XML Examples Source: https://context7.com/taublast/drawnui/llms.txt Demonstrates various ways to use SkiaButton in XML, including platform-styled buttons, custom styling with visual states, buttons with icons, and buttons with complex custom content layouts. ```xml ``` -------------------------------- ### Text Change Event Handling for Entry Controls Source: https://github.com/taublast/drawnui/blob/main/docs/_site/articles/fluent-extensions.html Provides examples of handling text changes for SkiaMauiEntry, SkiaMauiEditor, and SkiaLabel using the OnTextChanged event. ```csharp new SkiaMauiEntry() .OnTextChanged((entry, text) => { // Handle text changes Console.WriteLine($"Text changed to: {text}"); }); new SkiaMauiEditor() .OnTextChanged((editor, text) => { // Handle editor text changes }); new SkiaLabel() .OnTextChanged((label, text) => { // Handle label text changes via PropertyChanged }); ``` -------------------------------- ### Setup SkiaViewSwitcher Transition Animation Source: https://github.com/taublast/drawnui/blob/main/docs/_site/api/DrawnUi.Controls.SkiaViewSwitcher.html Configures and prepares the animation for transitioning between two views. It takes the transition type and the previous and new visible views as parameters. This method is asynchronous and returns a Task. ```csharp protected virtual Task SetupTransitionAnimation(DoubleViewTransitionType doubleViewTransitionType, SkiaControl previousVisibleView, SkiaControl newVisibleView) { // Implementation details for setting up transition animation return Task.CompletedTask; } ``` -------------------------------- ### StaticResourcesExtensions: Get All Parents Including Self Source: https://github.com/taublast/drawnui/blob/main/docs/_site/api/DrawnUi.Draw.SkiaProgress.html Collects all visual elements in the hierarchy starting from the given visual element up to the root. This includes the element itself. Part of the DrawnUi.Draw.StaticResourcesExtensions class. ```csharp public static IEnumerable GetAllWithMyselfParents(this VisualElement element) { // Implementation to traverse and collect parents yield return element; } ``` -------------------------------- ### Building and Running a DrawnUI App Source: https://github.com/taublast/drawnui/blob/main/docs/_site/articles/first-app.html Command-line instructions for building and running a DrawnUI application using the .NET CLI. These commands are standard for .NET projects and initiate the application's execution. ```bash dotnet build dotnet run ``` -------------------------------- ### Get All Parents Including Self (C#) Source: https://github.com/taublast/drawnui/blob/main/docs/_site/api/DrawnUi.Draw.VirtualScroll.html Retrieves a collection of all visual elements in the hierarchy, starting from the given element and including all its ancestors up to the root. This is useful for traversing the visual tree. ```csharp public static IEnumerable GetAllWithMyselfParents(this VisualElement element) { // Implementation details for getting all parents yield break; } ``` -------------------------------- ### DrawnUiBasePage XAML Structure Source: https://github.com/taublast/drawnui/blob/main/docs/articles/getting-started.md Defines a basic DrawnUi page structure using DrawnUiBasePage, including a Canvas with SkiaLayout, SkiaLabel, and SkiaButton. It demonstrates how to set rendering modes, gestures, and layout options. ```xml ``` -------------------------------- ### Trim Audio Samples by Timestamp (C#) Source: https://github.com/taublast/drawnui/blob/main/src/Maui/Addons/DrawnUi.Maui.Camera/PreRecordingTech.md Demonstrates how to trim audio samples to match the video duration when the audio capture starts before video encoding. It calculates the target start timestamp in nanoseconds and filters the audio samples to include only those within the video's duration. This ensures synchronized audio and video output. ```csharp var targetStartNs = lastSampleTimestamp - (long)(videoDurationMs * 1_000_000); allAudioSamples = allAudioSamples.Where(s => s.TimestampNs >= targetStartNs).ToArray(); ``` -------------------------------- ### SkiaShell - SetupRoot Source: https://github.com/taublast/drawnui/blob/main/docs/_site/api/DrawnUi.Controls.SkiaShell.html Sets up the main root layout control within the SkiaShell. ```APIDOC ## SetupRoot ### Description Sets up the main root layout control within the SkiaShell. ### Method `protected virtual void` ### Endpoint N/A (Internal method) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **shellLayout** (ISkiaControl) - The root layout control to set up. ### Request Example ```json { "shellLayout": "" } ``` ### Response #### Success Response (200) None #### Response Example None ``` -------------------------------- ### StaticResourcesExtensions: Get All Parents Including Self Source: https://github.com/taublast/drawnui/blob/main/docs/_site/api/DrawnUi.Draw.SkiaLayout.html Returns a collection of all visual elements in the hierarchy, starting from the given visual element and including all its ancestors. Useful for traversing the visual tree. ```csharp public static IEnumerable GetAllWithMyselfParents(this VisualElement element) { // Implementation to get all parents including the element itself return Enumerable.Empty(); } ``` -------------------------------- ### SkiaControl Rendering and Gradient Setup Source: https://github.com/taublast/drawnui/blob/main/docs/_site/api/DrawnUi.Controls.SkiaLottie.html Details methods for setting up gradients, creating shadows, and updating platform-specific shadow rendering. ```APIDOC ## SkiaControl Rendering and Gradient Setup ### Description This section describes methods related to advanced rendering features, including configuring gradients, generating shadows, and managing platform-specific shadow implementations. ### Methods - **SetupGradient(SKPaint paint, SkiaGradient gradient, SKRect rect)**: Configures a gradient for a given paint object and rectangle. - **CreateShadow(SkiaShadow shadow, float alpha)**: Creates a shadow effect with specified parameters. - **UpdatePlatformShadow()**: Updates the shadow rendering based on platform-specific requirements. - **PlatformShadow**: Property related to the platform's shadow implementation. - **HasPlatformClip()**: Checks if the platform has a clipping mechanism. - **GetDensity()**: Retrieves the screen density. ``` -------------------------------- ### SkiaViewSwitcher XAML Basic Usage Source: https://github.com/taublast/drawnui/blob/main/docs/_site/articles/controls/shell.html Illustrates the basic XAML setup for a SkiaViewSwitcher. This example focuses on defining transition types and durations, with views intended to be added programmatically. ```xaml ``` -------------------------------- ### Add DrawnUi Namespace to XAML Source: https://github.com/taublast/drawnui/blob/main/docs/_site/articles/getting-started.html Declares the DrawnUi XML namespace in a .NET MAUI XAML file. This allows you to use DrawnUI controls and elements directly within your XAML markup. ```xml ``` -------------------------------- ### Gradient and Shadow Setup Source: https://github.com/taublast/drawnui/blob/main/docs/_site/api/DrawnUi.Controls.GridLayout.html Methods for setting up gradients and creating shadows for the SkiaControl. ```APIDOC ## SkiaControl Gradient and Shadow Setup ### Description Provides methods to configure gradients and shadows for rendering effects within the SkiaControl. ### Methods - **SetupGradient(SKPaint paint, SkiaGradient gradient, SKRect bounds)** - **Description**: Configures the provided SKPaint object to use the specified gradient for rendering within the given bounds. - **Method**: POST - **Endpoint**: N/A (Method call) - **Parameters**: - **paint** (SKPaint) - Required - The paint object to configure. - **gradient** (SkiaGradient) - Required - The gradient definition. - **bounds** (SKRect) - Required - The rectangular area for the gradient. - **CreateShadow(SkiaShadow shadow, float opacity)** - **Description**: Creates shadow information based on the provided shadow definition and opacity. - **Method**: POST - **Endpoint**: N/A (Method call) - **Parameters**: - **shadow** (SkiaShadow) - Required - The definition of the shadow. - **opacity** (float) - Required - The opacity of the shadow. - **UpdatePlatformShadow()** - **Description**: Updates the platform-specific shadow rendering. - **Method**: POST - **Endpoint**: N/A (Method call) - **PlatformShadow** - **Description**: Gets or sets the platform-specific shadow properties. - **Method**: GET/SET - **Endpoint**: N/A (Property access) ### Response #### Success Response (200) - **Result** (Void or Shadow Object) - Description depends on the method or property accessed. #### Response Example ```json { "example": "Shadow updated." } ``` ``` -------------------------------- ### Gradient and Shadow Setup Source: https://github.com/taublast/drawnui/blob/main/docs/_site/api/DrawnUi.Draw.SkiaHotspotZoom.html Methods for setting up gradients and shadows for Skia rendering. ```APIDOC ## SkiaControl Gradient and Shadow Methods ### Description Methods for configuring gradients and shadows within the Skia rendering context. ### Methods - **SetupGradient(SKPaint, SkiaGradient, SKRect)**: Configures a gradient for a given SKPaint object. - **CreateShadow(SkiaShadow, float)**: Creates a shadow effect. - **UpdatePlatformShadow()**: Updates the platform-specific shadow. ``` -------------------------------- ### Get All Ancestors Including Self (C#) Source: https://github.com/taublast/drawnui/blob/main/docs/_site/api/DrawnUi.Draw.SkiaFrame.html Retrieves a collection of all visual elements in the hierarchy, starting from the given element and including all its ancestors up to the root. This is useful for traversal and analysis of the visual tree. ```csharp public static IEnumerable GetAllWithMyselfParents(this VisualElement element) { // Implementation details for getting all parents including self return Enumerable.Empty(); } ``` -------------------------------- ### SkiaGif Playback Control Source: https://github.com/taublast/drawnui/blob/main/docs/_site/articles/controls/animations.html Provides C# code examples for controlling the playback of a SkiaGif animation. This includes starting, stopping, seeking to a specific frame, and retrieving the total number of frames. ```csharp // Start the animation myGif.Start(); // Stop at current frame myGif.Stop(); // Jump to specific frame myGif.Seek(5); // Get total frames int total = myGif.Animation?.TotalFrames ?? 0; ``` -------------------------------- ### C# AVFoundation Muxing Pre-recorded and Live Audio/Video Source: https://github.com/taublast/drawnui/blob/main/src/Maui/Addons/DrawnUi.Maui.Camera/PreRecordingTech.md Illustrates the process of combining pre-recorded and live video and audio segments into a single composition using AVFoundation in C#. It details inserting tracks into an AVMutableComposition and exporting the final asset, utilizing the passthrough mode for efficiency. ```csharp using var composition = new AVMutableComposition(); var videoTrack = composition.AddMutableTrack(AVMediaTypes.Video, 0); // Insert pre-recording VIDEO at time 0 videoTrack.InsertTimeRange(preRecVideoRange, preRecVideoTrack, CMTime.Zero, out error); // Insert live recording VIDEO after pre-recording videoTrack.InsertTimeRange(liveVideoRange, liveRecVideoTrack, preRecAsset.Duration, out error); // Add pre-rec AUDIO at time 0 if (preRecAudioFilePath exists) { using var preRecAudioAsset = AVAsset.FromUrl(preRecAudioFilePath); var audioTrack = composition.AddMutableTrack(AVMediaTypes.Audio, 0); audioTrack.InsertTimeRange(preRecAudioRange, preRecAudioTracks[0], CMTime.Zero, out error); } // Add live AUDIO starting after pre-rec video duration if (liveAudioFilePath exists) { using var liveAudioAsset = AVAsset.FromUrl(liveAudioFilePath); // Get or create audio track var audioTrack = composition.TracksWithMediaType(AVMediaTypes.Audio)[0]; audioTrack.InsertTimeRange(liveAudioRange, liveAudioTracks[0], preRecVideoDuration, out error); } // Export with Passthrough (fast!) using var exporter = new AVAssetExportSession(composition, AVAssetExportSessionPreset.Passthrough); await exporter.ExportTaskAsync(); ``` -------------------------------- ### Install DocFX .NET Global Tool Source: https://github.com/taublast/drawnui/blob/main/docs/_site/README.html Installs DocFX as a .NET global tool, which is the recommended method for building documentation locally. This tool is essential for processing and generating the documentation files. ```bash dotnet tool install -g docfx ``` -------------------------------- ### Get DrawingContext Argument in C# Source: https://github.com/taublast/drawnui/blob/main/docs/_site/api/DrawnUi.Draw.DrawingContext.html Retrieves an optional argument from the DrawingContext using a string key. Returns null if the key is not found. Example usage demonstrates checking for a scale argument. ```csharp public object? GetArgument(string key) // Example: // if (ctx.GetArgument(ContextArguments.Scale.ToString()) is float zoomedScale) {} ```