From e3baba75ae2cbba1cf7d64a8dcecd65f05576e6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Tue, 20 Oct 2026 21:33:19 -0400 Subject: [PATCH 1/3] Improve Avalonia-to-Rust mapping with hierarchy upcasts, rsx!, signals, and view-model scanner - Add #[repr(transparent)] control wrappers, Deref inheritance, and Upcast - Add ergonomic tuple/scalar/hex From conversions, content_text/header_text helpers, and inline attached-property builders - Add deferred El view builders, rsx! macro, and reactive DataTemplate container pooling - Add AppScope fine-grained Signal, Memo, Effect, NodeRef, and IntoProp with two-way bindings - Add reactive_view_model! / prop! macros and ViewModelRustScanner (--scan-rust) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../ViewModelRustScanner.cs | 525 + .../Program.cs | 30 + rust/rustolonia-bindgen/src/emit_safe.rs | 592 +- rust/rustolonia-bindgen/src/geometry.rs | 116 + rust/rustolonia-sys/src/com.rs | 23 + .../src/.rustolonia-bindgen.owned.json | 2 +- rust/rustolonia/src/generated.rs | 114956 ++++++++++++--- rust/rustolonia/src/lib.rs | 8 +- rust/rustolonia/src/reactive.rs | 546 + rust/rustolonia/src/runtime.rs | 27 + rust/rustolonia/src/view.rs | 1075 + rust/rustolonia/src/view_model.rs | 148 + .../tests/declarative_and_reactive.rs | 350 + .../ViewModelRustScannerTests.cs | 148 + 14 files changed, 99910 insertions(+), 18636 deletions(-) create mode 100644 projection/Avalonia.Projection.Ir/ViewModelRustScanner.cs create mode 100644 rust/rustolonia/src/reactive.rs create mode 100644 rust/rustolonia/src/view.rs create mode 100644 rust/rustolonia/tests/declarative_and_reactive.rs create mode 100644 tests/Avalonia.Projection.Ir.Tests/ViewModelRustScannerTests.cs diff --git a/projection/Avalonia.Projection.Ir/ViewModelRustScanner.cs b/projection/Avalonia.Projection.Ir/ViewModelRustScanner.cs new file mode 100644 index 0000000..48a07ad --- /dev/null +++ b/projection/Avalonia.Projection.Ir/ViewModelRustScanner.cs @@ -0,0 +1,525 @@ +using System.Globalization; +using System.IO; +using System.Text.RegularExpressions; + +namespace Avalonia.Projection.Ir; + +/// +/// Scans Rust source files for #[view_model], #[view_model_enum], +/// #[prop], #[collection], and #[command] annotations and +/// produces or updates a canonical with deterministic IDs. +/// +public static class ViewModelRustScanner +{ + public static ViewModelIr ScanFileOrDirectory(string path, ViewModelIr? baseline = null) + { + if (File.Exists(path)) + return ScanSources([File.ReadAllText(path)], baseline); + + if (Directory.Exists(path)) + { + var files = Directory + .EnumerateFiles(path, "*.rs", SearchOption.AllDirectories) + .OrderBy(file => file, StringComparer.Ordinal) + .Select(File.ReadAllText) + .ToArray(); + return ScanSources(files, baseline); + } + + throw new FileNotFoundException($"Rust source path '{path}' does not exist.", path); + } + + public static ViewModelIr ScanSources(IEnumerable sources, ViewModelIr? baseline = null) + { + var combined = string.Join("\n", sources); + var enums = new List(); + if (baseline is not null) + enums.AddRange(baseline.Enums); + + foreach (Match enumMatch in EnumBlockRegex.Matches(combined)) + { + var attrText = enumMatch.Groups["attr"].Value; + var enumName = enumMatch.Groups["name"].Value; + var body = enumMatch.Groups["body"].Value; + var attrs = ParseAttributes(attrText); + var existing = enums.FirstOrDefault(e => e.Name == enumName); + var ns = GetAttr(attrs, "namespace") + ?? existing?.ManagedNamespace + ?? "Avalonia.Rust.Generated"; + var id = GetIntAttr(attrs, "id") + ?? existing?.Id + ?? NextId(enums.Select(e => e.Id)); + + var members = new List(); + long nextValue = 0; + foreach (Match memberMatch in EnumMemberRegex.Matches(body)) + { + var memberName = memberMatch.Groups["name"].Value; + if (string.IsNullOrWhiteSpace(memberName)) + continue; + var valueGroup = memberMatch.Groups["value"].Value; + var value = !string.IsNullOrWhiteSpace(valueGroup) + ? long.Parse(valueGroup, CultureInfo.InvariantCulture) + : nextValue; + nextValue = value + 1; + members.Add(new ViewModelEnumMember { Name = memberName, Value = value }); + } + + var definition = new ViewModelEnumDefinition + { + Id = id, + Name = enumName, + ManagedNamespace = ns, + Members = members, + }; + + var existingIndex = enums.FindIndex(e => e.Name == enumName); + if (existingIndex >= 0) + enums[existingIndex] = definition; + else + enums.Add(definition); + } + + var enumNames = enums.Select(e => e.Name).ToHashSet(StringComparer.Ordinal); + var commandsByStruct = ScanImplCommands(combined); + + var models = new List(); + if (baseline is not null) + models.AddRange(baseline.Models); + + var views = new List(); + if (baseline is not null) + views.AddRange(baseline.Views); + + // First pass: collect all scanned model struct names so nested model references resolve regardless of declaration order. + var knownModelNames = models.Select(m => m.Name).ToHashSet(StringComparer.Ordinal); + foreach (Match structMatch in StructBlockRegex.Matches(combined)) + { + var attrs = ParseAttributes(structMatch.Groups["attr"].Value); + var structName = structMatch.Groups["name"].Value; + var modelName = GetAttr(attrs, "name") ?? EnsureViewModelSuffix(structName); + knownModelNames.Add(modelName); + } + + foreach (Match structMatch in StructBlockRegex.Matches(combined)) + { + var attrText = structMatch.Groups["attr"].Value; + var structName = structMatch.Groups["name"].Value; + var body = structMatch.Groups["body"].Value; + var attrs = ParseAttributes(attrText); + + var modelName = GetAttr(attrs, "name") ?? EnsureViewModelSuffix(structName); + var existingModel = models.FirstOrDefault(m => m.Name == modelName); + var ns = GetAttr(attrs, "namespace") + ?? existingModel?.ManagedNamespace + ?? "Avalonia.Rust.Generated"; + var modelId = GetIntAttr(attrs, "id") + ?? existingModel?.Id + ?? NextId(models.Select(m => m.Id)); + + var properties = new List(); + var collections = new List(); + if (existingModel is not null) + { + properties.AddRange(existingModel.Properties); + collections.AddRange(existingModel.Collections); + } + + ScanFields(body, enumNames, knownModelNames, properties, collections); + + var commands = new List(); + if (existingModel is not null) + commands.AddRange(existingModel.Commands); + + if (commandsByStruct.TryGetValue(structName, out var scannedCommands)) + { + foreach (var cmd in scannedCommands) + { + var existingCmd = commands.FirstOrDefault(c => c.Name == cmd.Name); + var cmdId = cmd.ExplicitId + ?? existingCmd?.Id + ?? NextId(commands.Select(c => c.Id)); + var built = new ViewModelCommand + { + Id = cmdId, + Name = cmd.Name, + IsAsync = cmd.IsAsync, + ParameterProperty = cmd.ParameterProperty ?? existingCmd?.ParameterProperty, + ResultModelName = cmd.ResultModelName ?? existingCmd?.ResultModelName, + SupportsProgress = cmd.SupportsProgress || (existingCmd?.SupportsProgress ?? false), + SupportsCancellation = cmd.SupportsCancellation || (existingCmd?.SupportsCancellation ?? false), + }; + var idx = commands.FindIndex(c => c.Name == cmd.Name); + if (idx >= 0) + commands[idx] = built; + else + commands.Add(built); + } + } + + var modelDef = new ViewModelDefinition + { + Id = modelId, + Name = modelName, + ManagedNamespace = ns, + Properties = properties, + Collections = collections, + Maps = existingModel?.Maps ?? [], + Commands = commands, + Menus = existingModel?.Menus ?? [], + RecentFiles = existingModel?.RecentFiles, + DisplayPath = GetAttr(attrs, "display_path") ?? existingModel?.DisplayPath, + ThemeVariantProperty = GetAttr(attrs, "theme_variant_property") ?? existingModel?.ThemeVariantProperty, + }; + + var existingModelIndex = models.FindIndex(m => m.Name == modelName); + if (existingModelIndex >= 0) + models[existingModelIndex] = modelDef; + else + models.Add(modelDef); + + if (GetAttr(attrs, "view") is { } viewName) + { + var existingView = views.FirstOrDefault(v => v.Name == viewName); + var viewId = GetIntAttr(attrs, "view_id") + ?? existingView?.Id + ?? NextId(views.Select(v => v.Id)); + var viewType = GetAttr(attrs, "view_type") + ?? existingView?.ManagedTypeName + ?? $"{ns}.{viewName}"; + var dynamicBindings = HasFlag(attrs, "dynamic_bindings") + || (existingView?.DynamicBindings ?? false); + var viewDef = new ViewDefinition + { + Id = viewId, + Name = viewName, + Model = modelName, + ManagedTypeName = viewType, + DynamicBindings = dynamicBindings, + Converters = existingView?.Converters ?? [], + }; + var existingViewIndex = views.FindIndex(v => v.Name == viewName); + if (existingViewIndex >= 0) + views[existingViewIndex] = viewDef; + else + views.Add(viewDef); + } + } + + var ir = new ViewModelIr + { + Version = baseline?.Version ?? ViewModelIr.CurrentVersion, + Enums = enums, + Models = models, + Views = views, + Converters = baseline?.Converters ?? [], + }; + ir.Validate(); + return ir; + } + + private static void ScanFields( + string body, + HashSet enumNames, + HashSet knownModelNames, + List properties, + List collections) + { + foreach (Match fieldMatch in FieldRegex.Matches(body)) + { + var attrKind = fieldMatch.Groups["kind"].Value; + var attrArgs = ParseAttributes(fieldMatch.Groups["attr"].Value); + var fieldName = fieldMatch.Groups["name"].Value; + var rustType = fieldMatch.Groups["type"].Value.Trim(); + + var memberName = GetAttr(attrArgs, "name") ?? ToPascalCase(fieldName); + + if (attrKind == "collection" || rustType.StartsWith("Vec<", StringComparison.Ordinal)) + { + var innerType = ExtractGenericArg(rustType, "Vec") ?? rustType; + var elementModel = GetAttr(attrArgs, "model"); + ViewModelValueKind elementKind; + if (elementModel is not null) + { + elementKind = ViewModelValueKind.Model; + } + else if (innerType is "String" or "&str") + { + elementKind = ViewModelValueKind.String; + } + else if (innerType is "i64" or "i32" or "isize") + { + elementKind = ViewModelValueKind.Integer; + } + else if (innerType is "f64" or "f32") + { + elementKind = ViewModelValueKind.Double; + } + else + { + elementKind = ViewModelValueKind.Model; + elementModel = EnsureViewModelSuffix(innerType); + } + + var existingCol = collections.FirstOrDefault(c => c.Name == memberName); + var colId = GetIntAttr(attrArgs, "id") + ?? existingCol?.Id + ?? NextId(collections.Select(c => c.Id)); + + var colDef = new ViewModelCollection + { + Id = colId, + Name = memberName, + ElementKind = elementKind, + ElementModelName = elementModel ?? existingCol?.ElementModelName, + Table = existingCol?.Table, + Window = existingCol?.Window, + Recursive = HasFlag(attrArgs, "recursive") || (existingCol?.Recursive ?? false), + Tree = existingCol?.Tree, + }; + var idx = collections.FindIndex(c => c.Name == memberName); + if (idx >= 0) + collections[idx] = colDef; + else + collections.Add(colDef); + continue; + } + + var isOption = ExtractGenericArg(rustType, "Option") is { } optInner; + var coreType = ExtractGenericArg(rustType, "Option") ?? rustType; + var nullable = isOption || HasFlag(attrArgs, "nullable"); + var writable = HasFlag(attrArgs, "writable"); + + var explicitEnum = GetAttr(attrArgs, "enum"); + var explicitModel = GetAttr(attrArgs, "model"); + + ViewModelValueKind propKind; + string? enumName = null; + string? nestedModelName = null; + + if (explicitModel is not null) + { + propKind = ViewModelValueKind.Model; + nestedModelName = explicitModel; + nullable = true; + writable = false; + } + else if (explicitEnum is not null || enumNames.Contains(coreType)) + { + propKind = ViewModelValueKind.Enum; + enumName = explicitEnum ?? coreType; + } + else if (coreType is "String" or "&str") + { + propKind = ViewModelValueKind.String; + } + else if (coreType is "i64" or "i32" or "isize") + { + propKind = ViewModelValueKind.Integer; + } + else if (coreType == "bool") + { + propKind = ViewModelValueKind.Boolean; + } + else if (coreType is "f64" or "f32") + { + propKind = ViewModelValueKind.Double; + } + else if (knownModelNames.Contains(coreType) || knownModelNames.Contains(EnsureViewModelSuffix(coreType))) + { + propKind = ViewModelValueKind.Model; + nestedModelName = knownModelNames.Contains(coreType) ? coreType : EnsureViewModelSuffix(coreType); + nullable = true; + writable = false; + } + else + { + continue; + } + + var existingProp = properties.FirstOrDefault(p => p.Name == memberName); + var propId = GetIntAttr(attrArgs, "id") + ?? existingProp?.Id + ?? NextId(properties.Select(p => p.Id)); + + var initialRaw = GetAttr(attrArgs, "initial"); + string? initialString = existingProp?.InitialString; + long? initialInteger = existingProp?.InitialInteger; + bool? initialBoolean = existingProp?.InitialBoolean; + double? initialDouble = existingProp?.InitialDouble; + + if (initialRaw is not null) + { + switch (propKind) + { + case ViewModelValueKind.String: + initialString = initialRaw; + break; + case ViewModelValueKind.Integer: + case ViewModelValueKind.Enum: + initialInteger = long.Parse(initialRaw, CultureInfo.InvariantCulture); + break; + case ViewModelValueKind.Boolean: + initialBoolean = bool.Parse(initialRaw); + break; + case ViewModelValueKind.Double: + initialDouble = double.Parse(initialRaw, CultureInfo.InvariantCulture); + break; + } + } + + var propDef = new ViewModelProperty + { + Id = propId, + Name = memberName, + Kind = propKind, + Writable = writable, + Nullable = nullable, + EnumName = enumName, + ModelName = nestedModelName, + InitialString = initialString, + InitialInteger = initialInteger, + InitialBoolean = initialBoolean, + InitialDouble = initialDouble, + }; + + var propIdx = properties.FindIndex(p => p.Name == memberName); + if (propIdx >= 0) + properties[propIdx] = propDef; + else + properties.Add(propDef); + } + } + + private sealed record ScannedCommand( + int? ExplicitId, + string Name, + bool IsAsync, + string? ParameterProperty, + string? ResultModelName, + bool SupportsProgress, + bool SupportsCancellation); + + private static Dictionary> ScanImplCommands(string source) + { + var result = new Dictionary>(StringComparer.Ordinal); + foreach (Match implMatch in ImplBlockRegex.Matches(source)) + { + var structName = implMatch.Groups["name"].Value; + var body = implMatch.Groups["body"].Value; + if (!result.TryGetValue(structName, out var list)) + { + list = []; + result[structName] = list; + } + + foreach (Match cmdMatch in CommandFnRegex.Matches(body)) + { + var attrs = ParseAttributes(cmdMatch.Groups["attr"].Value); + var fnName = cmdMatch.Groups["name"].Value; + var cmdName = GetAttr(attrs, "name") ?? ToPascalCase(fnName); + var isAsync = HasFlag(attrs, "async") || HasFlag(attrs, "is_async"); + var supportsProgress = HasFlag(attrs, "progress") || HasFlag(attrs, "supports_progress"); + var supportsCancellation = HasFlag(attrs, "cancellable") || HasFlag(attrs, "supports_cancellation"); + if (supportsProgress || supportsCancellation) + isAsync = true; + + list.Add(new ScannedCommand( + GetIntAttr(attrs, "id"), + cmdName, + isAsync, + GetAttr(attrs, "parameter_property"), + GetAttr(attrs, "result_model"), + supportsProgress, + supportsCancellation)); + } + } + return result; + } + + private static Dictionary ParseAttributes(string raw) + { + var dict = new Dictionary(StringComparer.Ordinal); + if (string.IsNullOrWhiteSpace(raw)) + return dict; + + foreach (Match m in AttrItemRegex.Matches(raw)) + { + var key = m.Groups["key"].Value; + if (m.Groups["str"].Success) + dict[key] = m.Groups["str"].Value; + else if (m.Groups["val"].Success) + dict[key] = m.Groups["val"].Value; + else + dict[key] = null; + } + return dict; + } + + private static string? GetAttr(Dictionary attrs, string key) => + attrs.TryGetValue(key, out var val) ? val : null; + + private static int? GetIntAttr(Dictionary attrs, string key) => + attrs.TryGetValue(key, out var val) && val is not null && int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsed) + ? parsed + : null; + + private static bool HasFlag(Dictionary attrs, string key) => + attrs.TryGetValue(key, out var val) && (val is null || string.Equals(val, "true", StringComparison.OrdinalIgnoreCase)); + + private static int NextId(IEnumerable existing) + { + var max = 0; + foreach (var id in existing) + { + if (id > max) + max = id; + } + return max + 1; + } + + private static string EnsureViewModelSuffix(string name) => + name.EndsWith("ViewModel", StringComparison.Ordinal) ? name : name + "ViewModel"; + + private static string? ExtractGenericArg(string rustType, string wrapper) + { + var prefix = wrapper + "<"; + if (rustType.StartsWith(prefix, StringComparison.Ordinal) && rustType.EndsWith(">", StringComparison.Ordinal)) + return rustType[prefix.Length..^1].Trim(); + return null; + } + + private static string ToPascalCase(string snake) + { + var parts = snake.Split('_', StringSplitOptions.RemoveEmptyEntries); + return string.Concat(parts.Select(part => char.ToUpperInvariant(part[0]) + part[1..])); + } + + private static readonly Regex EnumBlockRegex = new( + @"#\[(?:rustolonia::)?view_model_enum(?:\((?[^)]*)\))?\]\s*(?:#\[[^\]]*\]\s*)*(?:pub(?:\([^)]*\))?\s+)?enum\s+(?[A-Za-z_][A-Za-z0-9_]*)\s*\{(?[^}]*)\}", + RegexOptions.Compiled | RegexOptions.Singleline); + + private static readonly Regex EnumMemberRegex = new( + @"(?[A-Za-z_][A-Za-z0-9_]*)\s*(?:=\s*(?-?[0-9]+))?\s*,?", + RegexOptions.Compiled); + + private static readonly Regex StructBlockRegex = new( + @"#\[(?:rustolonia::)?view_model(?:\((?[^)]*)\))?\]\s*(?:#\[[^\]]*\]\s*)*(?:pub(?:\([^)]*\))?\s+)?struct\s+(?[A-Za-z_][A-Za-z0-9_]*)\s*\{(?[^}]*)\}", + RegexOptions.Compiled | RegexOptions.Singleline); + + private static readonly Regex FieldRegex = new( + @"#\[(?prop|collection)(?:\((?[^)]*)\))?\]\s*(?:pub(?:\([^)]*\))?\s+)?(?[A-Za-z_][A-Za-z0-9_]*)\s*:\s*(?[^,\n}]+)", + RegexOptions.Compiled); + + private static readonly Regex ImplBlockRegex = new( + @"impl\s+(?[A-Za-z_][A-Za-z0-9_]*)\s*\{(?(?:[^{}]|\{[^{}]*\})*)\}", + RegexOptions.Compiled | RegexOptions.Singleline); + + private static readonly Regex CommandFnRegex = new( + @"#\[command(?:\((?[^)]*)\))?\]\s*(?:pub(?:\([^)]*\))?\s+)?(?:async\s+)?fn\s+(?[A-Za-z_][A-Za-z0-9_]*)", + RegexOptions.Compiled); + + private static readonly Regex AttrItemRegex = new( + @"(?[A-Za-z_][A-Za-z0-9_]*)\s*(?:=\s*(?:""(?[^""]*)""|(?[^,\s)]+)))?", + RegexOptions.Compiled); +} diff --git a/projection/Avalonia.ViewModelProjection.Tool/Program.cs b/projection/Avalonia.ViewModelProjection.Tool/Program.cs index ca3b43a..9a04e06 100644 --- a/projection/Avalonia.ViewModelProjection.Tool/Program.cs +++ b/projection/Avalonia.ViewModelProjection.Tool/Program.cs @@ -25,6 +25,34 @@ return 0; } +if (args.Length == 3 && args[0] == "--scan-rust") +{ + var sourcePath = Path.GetFullPath(args[1]); + var irFile = Path.GetFullPath(args[2]); + var baseline = File.Exists(irFile) ? ViewModelIr.FromJson(File.ReadAllText(irFile)) : null; + var scanned = ViewModelRustScanner.ScanFileOrDirectory(sourcePath, baseline); + var json = scanned.ToJson().Replace(Environment.NewLine, "\n") + "\n"; + if (checkMode) + { + if (!File.Exists(irFile)) + { + Console.Error.WriteLine($"Missing view-model IR file: {irFile}"); + return 1; + } + var current = File.ReadAllText(irFile).Replace("\r\n", "\n"); + if (!string.Equals(current, json, StringComparison.Ordinal)) + { + Console.Error.WriteLine($"View-model IR file is out of sync with Rust source: {irFile}"); + return 1; + } + Console.WriteLine($"View-model IR scan check passed for {irFile}."); + return 0; + } + File.WriteAllText(irFile, json); + Console.WriteLine($"Scanned Rust view models into {irFile}."); + return 0; +} + var externalRust = args.Length == 6 && args[5] == "--external-rust"; if (args.Length != 5 && !externalRust) { @@ -32,6 +60,8 @@ "Usage: Avalonia.ViewModelProjection.Tool [--check] [--external-rust]"); Console.Error.WriteLine( " Avalonia.ViewModelProjection.Tool --normalize "); + Console.Error.WriteLine( + " Avalonia.ViewModelProjection.Tool [--check] --scan-rust "); return 2; } diff --git a/rust/rustolonia-bindgen/src/emit_safe.rs b/rust/rustolonia-bindgen/src/emit_safe.rs index 9f77474..79e861f 100644 --- a/rust/rustolonia-bindgen/src/emit_safe.rs +++ b/rust/rustolonia-bindgen/src/emit_safe.rs @@ -45,6 +45,16 @@ pub(crate) fn emit_safe_module(ir: &ProjectionIr) -> String { \x20 pub(crate) fn to_abi(self) -> sys::AvnPixelPoint {\n\ \x20 sys::AvnPixelPoint { x: self.x, y: self.y }\n\ \x20 }\n\ + }\n\n\ + impl From<(i32, i32)> for PixelPoint {\n\ + \x20 fn from((x, y): (i32, i32)) -> Self {\n\ + \x20 Self::new(x, y)\n\ + \x20 }\n\ + }\n\n\ + impl From<[i32; 2]> for PixelPoint {\n\ + \x20 fn from([x, y]: [i32; 2]) -> Self {\n\ + \x20 Self::new(x, y)\n\ + \x20 }\n\ }\n\n", ); if ir @@ -197,6 +207,16 @@ fn emit_brush() -> String { \x20 fn from(color: Color) -> Self {\n\ \x20 Self::solid(color)\n\ \x20 }\n\ + }\n\n\ + impl From<(u8, u8, u8)> for Brush {\n\ + \x20 fn from((r, g, b): (u8, u8, u8)) -> Self {\n\ + \x20 Self::solid(Color::rgb(r, g, b))\n\ + \x20 }\n\ + }\n\n\ + impl From<(u8, u8, u8, u8)> for Brush {\n\ + \x20 fn from((a, r, g, b): (u8, u8, u8, u8)) -> Self {\n\ + \x20 Self::solid(Color::new(a, r, g, b))\n\ + \x20 }\n\ }\n\n", ) } @@ -458,6 +478,16 @@ fn emit_gradient_brush() -> String { \x20 Self::Solid(Brush::solid(color))\n\ \x20 }\n\ }\n\n\ + impl From<(u8, u8, u8)> for Paint {\n\ + \x20 fn from((r, g, b): (u8, u8, u8)) -> Self {\n\ + \x20 Self::Solid(Brush::solid(Color::rgb(r, g, b)))\n\ + \x20 }\n\ + }\n\n\ + impl From<(u8, u8, u8, u8)> for Paint {\n\ + \x20 fn from((a, r, g, b): (u8, u8, u8, u8)) -> Self {\n\ + \x20 Self::Solid(Brush::solid(Color::new(a, r, g, b)))\n\ + \x20 }\n\ + }\n\n\ impl From for Paint {\n\ \x20 fn from(brush: LinearGradientBrush) -> Self {\n\ \x20 Self::LinearGradient(brush)\n\ @@ -579,8 +609,13 @@ fn emit_type( flags_enums: &std::collections::HashSet<&str>, ) -> String { let safe_name = interface_suffix(&ty.name); + let has_text_block = ir + .types + .iter() + .any(|candidate| candidate.name == "IAvnTextBlock" && candidate.is_constructible); let mut out = format!( - "#[derive(Clone, Debug)]\n\ + "#[repr(transparent)]\n\ + #[derive(Clone, Debug)]\n\ pub struct {safe_name} {{\n\ \x20 pub(crate) raw: sys::ComPtr,\n\ }}\n\n\ @@ -596,6 +631,13 @@ fn emit_type( \x20 }}\n", factory_name = to_snake(safe_name) )); + if has_text_block { + out.push_str( + " pub fn el() -> crate::view::El {\n\ + \x20 crate::view::El::new(Self::new)\n\ + \x20 }\n", + ); + } } let reserved_methods: std::collections::HashSet = lineage(ir, ty) @@ -621,6 +663,35 @@ fn emit_type( \x20 }\n", ); } + if has_text_block + && property.can_write + && property.kind == "ComInterface" + && property.interface_name.as_deref().map(simple_name) == Some("IAvnControl") + { + if property.name == "Content" { + out.push_str( + " pub fn set_content_text(&self, value: impl AsRef) -> Result<()> {\n\ + \x20 let text_block = TextBlock::new()?.text(value)?;\n\ + \x20 self.set_content(Some(&text_block))\n\ + \x20 }\n\ + \x20 pub fn content_text(self, value: impl AsRef) -> Result {\n\ + \x20 self.set_content_text(value)?;\n\ + \x20 Ok(self)\n\ + \x20 }\n", + ); + } else if property.name == "Header" { + out.push_str( + " pub fn set_header_text(&self, value: impl AsRef) -> Result<()> {\n\ + \x20 let text_block = TextBlock::new()?.text(value)?;\n\ + \x20 self.set_header(Some(&text_block))\n\ + \x20 }\n\ + \x20 pub fn header_text(self, value: impl AsRef) -> Result {\n\ + \x20 self.set_header_text(value)?;\n\ + \x20 Ok(self)\n\ + \x20 }\n", + ); + } + } } for method in &owner.methods { out.push_str(&emit_method(ty, method)); @@ -636,18 +707,154 @@ fn emit_type( { out.push_str(&emit_attached_property(property, ir)); } + if is_control(ir, ty) { + for property in &ir.attached_properties { + out.push_str(&emit_inline_attached_property(property, ir)); + } + } out.push_str("}\n\n"); - if is_control(ir, ty) { + if let Some(base_full_name) = &ty.base_full_name { + let parent = ir + .types + .iter() + .find(|candidate| &candidate.full_name == base_full_name) + .expect("base type must be present in projection IR"); + let parent_safe = interface_suffix(&parent.name); out.push_str(&format!( - "impl AsControl for {safe_name} {{\n\ - \x20 fn as_control(&self) -> Result> {{\n\ - \x20 Ok(self.raw.query_interface()?)\n\ + "impl std::ops::Deref for {safe_name} {{\n\ + \x20 type Target = {parent_safe};\n\ + \x20 fn deref(&self) -> &Self::Target {{\n\ + \x20 unsafe {{ &*(self as *const Self as *const Self::Target) }}\n\ \x20 }}\n\ - }}\n" + }}\n\n" )); } + for ancestor in lineage(ir, ty) { + if ancestor.full_name == ty.full_name { + continue; + } + let ancestor_safe = interface_suffix(&ancestor.name); + out.push_str(&format!( + "unsafe impl crate::Upcast<{ancestor_safe}> for {safe_name} {{\n\ + \x20 fn upcast(&self) -> {ancestor_safe} {{\n\ + \x20 {ancestor_safe} {{\n\ + \x20 raw: unsafe {{ self.raw.cast_clone() }},\n\ + \x20 }}\n\ + \x20 }}\n\ + \x20 fn upcast_ref(&self) -> &{ancestor_safe} {{\n\ + \x20 unsafe {{ &*(self as *const Self as *const {ancestor_safe}) }}\n\ + \x20 }}\n\ + }}\n\n\ + impl AsRef<{ancestor_safe}> for {safe_name} {{\n\ + \x20 fn as_ref(&self) -> &{ancestor_safe} {{\n\ + \x20 >::upcast_ref(self)\n\ + \x20 }}\n\ + }}\n\n" + )); + } + + if is_control(ir, ty) { + if safe_name == "Control" { + out.push_str( + "impl AsControl for Control {\n\ + \x20 fn as_control(&self) -> Result> {\n\ + \x20 Ok(self.raw.clone())\n\ + \x20 }\n\ + }\n", + ); + } else { + out.push_str(&format!( + "impl AsControl for {safe_name} {{\n\ + \x20 fn as_control(&self) -> Result> {{\n\ + \x20 Ok(self.raw.query_interface()?)\n\ + \x20 }}\n\ + }}\n" + )); + } + } + + if ty.is_constructible && has_text_block { + out.push('\n'); + out.push_str(&emit_el_type(ir, ty, &reserved_methods, flags_enums)); + } + + fn emit_inline_attached_property( + property: &crate::ir::ProjectedAttachedProperty, + ir: &ProjectionIr, + ) -> String { + let owner_type = &property.owner_name; + let owner = to_snake(owner_type); + let name = to_snake(&property.name); + if property.kind == "StringUtf16" { + let get_type = if property.is_nullable { + "Option" + } else { + "String" + }; + return format!( + " pub fn get_{owner}_{name}(&self) -> Result<{get_type}> {{\n\ + \x20 {owner_type}::get_{name}(self)\n\ + \x20 }}\n\ + \x20 pub fn set_{owner}_{name}(&self, value: impl AsRef) -> Result<()> {{\n\ + \x20 {owner_type}::set_{name}(self, value)\n\ + \x20 }}\n\ + \x20 pub fn {owner}_{name}(self, value: impl AsRef) -> Result {{\n\ + \x20 {owner_type}::set_{name}(&self, value)?;\n\ + \x20 Ok(self)\n\ + \x20 }}\n" + ); + } + let enum_name = simple_name(&property.managed_type_name); + let is_enum = ir + .enums + .iter() + .any(|projected_enum| projected_enum.full_name == property.managed_type_name); + let (get_type, set_arg, set_forward) = if is_enum { + ( + enum_name.to_string(), + enum_name.to_string(), + "value".to_string(), + ) + } else if property.kind == "TimeSpanI64" { + ( + "std::time::Duration".to_string(), + "std::time::Duration".to_string(), + "value".to_string(), + ) + } else if let Some(geometry) = geometry::find(&property.kind) { + if property.is_nullable { + ( + format!("Option<{}>", geometry.safe_name), + format!("impl Into>", geometry.safe_name), + "value.into()".to_string(), + ) + } else { + ( + geometry.safe_name.to_string(), + format!("impl Into<{}>", geometry.safe_name), + "value.into()".to_string(), + ) + } + } else { + let scalar = rust_scalar_kind(&property.kind).to_string(); + (scalar.clone(), scalar, "value".to_string()) + }; + format!( + " pub fn get_{owner}_{name}(&self) -> Result<{get_type}> {{\n\ + \x20 {owner_type}::get_{name}(self)\n\ + \x20 }}\n\ + \x20 pub fn set_{owner}_{name}(&self, value: {set_arg}) -> Result<()> {{\n\ + \x20 {owner_type}::set_{name}(self, {set_forward})\n\ + \x20 }}\n\ + \x20 pub fn {owner}_{name}(self, value: {set_arg}) -> Result {{\n\ + \x20 {owner_type}::set_{name}(&self, {set_forward})?;\n\ + \x20 Ok(self)\n\ + \x20 }}\n" + ) + } + fn emit_attached_property( property: &crate::ir::ProjectedAttachedProperty, ir: &ProjectionIr, @@ -742,6 +949,367 @@ fn emit_type( out } +fn emit_el_type( + ir: &ProjectionIr, + ty: &ProjectedType, + reserved_methods: &std::collections::HashSet, + flags_enums: &std::collections::HashSet<&str>, +) -> String { + let safe_name = interface_suffix(&ty.name); + let mut out = format!("impl crate::view::El<{safe_name}> {{\n"); + let all_events: Vec<&ProjectedEvent> = lineage(ir, ty) + .into_iter() + .flat_map(|owner| owner.events.iter()) + .collect(); + let has_event = |name: &str| all_events.iter().any(|event| event.name == name); + let all_props: Vec<&ProjectedProperty> = lineage(ir, ty) + .into_iter() + .flat_map(|owner| owner.properties.iter()) + .collect(); + + for owner in lineage(ir, ty) { + for property in &owner.properties { + let snake = to_snake(&property.name); + let builder = if property.kind == "Bool" || property.kind == "NullableBool" { + match snake.strip_prefix("is_") { + Some(stripped) if !reserved_methods.contains(stripped) => stripped, + _ => snake.as_str(), + } + } else { + snake.as_str() + }; + + if property.kind == "ComCollection" && property.name == "Children" { + out.push_str( + " pub fn child(self, value: impl crate::view::IntoChildEl + 'static) -> Self {\n\ + \x20 self.with_op(move |scope, control| {\n\ + \x20 let built = value.into_child_el().build(scope)?;\n\ + \x20 control.children()?.add(built)\n\ + \x20 })\n\ + \x20 }\n\ + \x20 pub fn children_iter(mut self, children: I) -> Self\n\ + \x20 where\n\ + \x20 I: IntoIterator,\n\ + \x20 C: crate::view::IntoChildEl + 'static,\n\ + \x20 {\n\ + \x20 for child in children {\n\ + \x20 self = self.child(child);\n\ + \x20 }\n\ + \x20 self\n\ + \x20 }\n", + ); + } + if property.kind == "ComCollection" && property.name == "Items" { + out.push_str( + " pub fn item(self, value: impl crate::view::IntoChildEl + 'static) -> Self {\n\ + \x20 self.with_op(move |scope, control| {\n\ + \x20 let built = value.into_child_el().build(scope)?;\n\ + \x20 control.items()?.add(built)\n\ + \x20 })\n\ + \x20 }\n\ + \x20 pub fn items_iter(mut self, items: I) -> Self\n\ + \x20 where\n\ + \x20 I: IntoIterator,\n\ + \x20 C: crate::view::IntoChildEl + 'static,\n\ + \x20 {\n\ + \x20 for item in items {\n\ + \x20 self = self.item(item);\n\ + \x20 }\n\ + \x20 self\n\ + \x20 }\n", + ); + } + + if !property.can_write { + continue; + } + + match property.kind.as_str() { + "ComInterface" => { + let safe = interface_suffix(simple_name( + property.interface_name.as_deref().expect("interfaceName"), + )); + if safe == "Control" { + if property.is_nullable { + out.push_str(&format!( + " pub fn {builder}(self, value: impl crate::view::IntoContentEl + 'static) -> Self {{\n\ + \x20 self.with_op(move |scope, control| {{\n\ + \x20 let built = value.into_content_el().map(|el| el.build(scope)).transpose()?;\n\ + \x20 control.set_{builder}(built.as_ref().map(|c| c as &dyn AsControl))\n\ + \x20 }})\n\ + \x20 }}\n" + )); + } else { + out.push_str(&format!( + " pub fn {builder}(self, value: impl crate::view::IntoChildEl + 'static) -> Self {{\n\ + \x20 self.with_op(move |scope, control| {{\n\ + \x20 let built = value.into_child_el().build(scope)?;\n\ + \x20 control.set_{builder}(built)\n\ + \x20 }})\n\ + \x20 }}\n" + )); + } + } else if property.is_nullable { + out.push_str(&format!( + " pub fn {builder}(self, value: Option<{safe}>) -> Self {{\n\ + \x20 self.with_op(move |_, control| control.set_{builder}(value.as_ref()))\n\ + \x20 }}\n" + )); + } else { + out.push_str(&format!( + " pub fn {builder}(self, value: {safe}) -> Self {{\n\ + \x20 self.with_op(move |_, control| control.set_{builder}(&value))\n\ + \x20 }}\n" + )); + } + } + "ComCollection" => {} + "DataTemplate" => { + out.push_str(&format!( + " pub fn {builder}(self, value: Option) -> Self {{\n\ + \x20 self.with_op(move |_, control| control.set_{builder}(value.as_ref()))\n\ + \x20 }}\n" + )); + } + "Command" | "ItemFilter" | "TextFilter" | "ItemSelector" | "TextSelector" + | "PopupPlacement" | "AsyncPopulator" => { + let full = + simple_name(property.interface_name.as_deref().expect("interfaceName")); + out.push_str(&format!( + " pub fn {builder}(self, value: Option>) -> Self {{\n\ + \x20 self.with_op(move |_, control| control.set_{builder}(value.as_ref()))\n\ + \x20 }}\n" + )); + } + _ => { + let prop_type = if property.kind == "StringUtf16" { + "String".to_string() + } else if property.kind == "Brush" { + "Option".to_string() + } else if property.kind == "Variant" { + "Variant".to_string() + } else if property.kind == "TimeSpanI64" { + "std::time::Duration".to_string() + } else if property.kind == "PixelPointI32" { + "PixelPoint".to_string() + } else { + safe_scalar_type(property, flags_enums) + }; + + if property.name == "Text" + && property.kind == "StringUtf16" + && property.can_read + && has_event("TextChanged") + { + let get_expr = if property.is_nullable { + "|c: &_| c.get_text().map(|v| v.unwrap_or_default())" + } else { + "|c: &_| c.get_text()" + }; + out.push_str(&format!( + " pub fn {builder}(self, value: impl crate::view::IntoProp<{prop_type}, M> + 'static) -> Self {{\n\ + \x20 let binding = value.into_prop();\n\ + \x20 self.with_op(move |scope, control| {{\n\ + \x20 crate::view::apply_two_way_prop(\n\ + \x20 scope,\n\ + \x20 control,\n\ + \x20 binding,\n\ + \x20 |c, v| c.set_{builder}(v),\n\ + \x20 {get_expr},\n\ + \x20 |c, mut cb| c.subscribe_text_changed(move |_| cb()),\n\ + \x20 )\n\ + \x20 }})\n\ + \x20 }}\n" + )); + } else if property.name == "IsChecked" + && property.kind == "NullableBool" + && property.can_read + && has_event("IsCheckedChanged") + { + out.push_str(&format!( + " pub fn {builder}(self, value: impl crate::view::IntoProp<{prop_type}, M> + 'static) -> Self {{\n\ + \x20 let binding = value.into_prop();\n\ + \x20 self.with_op(move |scope, control| {{\n\ + \x20 crate::view::apply_two_way_prop(\n\ + \x20 scope,\n\ + \x20 control,\n\ + \x20 binding,\n\ + \x20 |c, v| c.set_{builder}(v),\n\ + \x20 |c| c.get_is_checked(),\n\ + \x20 |c, mut cb| c.subscribe_is_checked_changed(move |_| cb()),\n\ + \x20 )\n\ + \x20 }})\n\ + \x20 }}\n" + )); + } else if property.name == "Value" + && property.kind == "F64" + && property.can_read + && has_event("ValueChanged") + { + out.push_str(&format!( + " pub fn {builder}(self, value: impl crate::view::IntoProp<{prop_type}, M> + 'static) -> Self {{\n\ + \x20 let binding = value.into_prop();\n\ + \x20 self.with_op(move |scope, control| {{\n\ + \x20 crate::view::apply_two_way_prop(\n\ + \x20 scope,\n\ + \x20 control,\n\ + \x20 binding,\n\ + \x20 |c, v| c.set_{builder}(v),\n\ + \x20 |c| c.get_value(),\n\ + \x20 |c, mut cb| c.subscribe_value_changed(move |_| cb()),\n\ + \x20 )\n\ + \x20 }})\n\ + \x20 }}\n" + )); + } else if property.name == "SelectedIndex" + && property.kind == "I32" + && property.can_read + && has_event("SelectionChanged") + { + out.push_str(&format!( + " pub fn {builder}(self, value: impl crate::view::IntoProp<{prop_type}, M> + 'static) -> Self {{\n\ + \x20 let binding = value.into_prop();\n\ + \x20 self.with_op(move |scope, control| {{\n\ + \x20 crate::view::apply_two_way_prop(\n\ + \x20 scope,\n\ + \x20 control,\n\ + \x20 binding,\n\ + \x20 |c, v| c.set_{builder}(v),\n\ + \x20 |c| c.get_selected_index(),\n\ + \x20 |c, mut cb| c.subscribe_selection_changed(move |_| cb()),\n\ + \x20 )\n\ + \x20 }})\n\ + \x20 }}\n" + )); + } else { + out.push_str(&format!( + " pub fn {builder}(self, value: impl crate::view::IntoProp<{prop_type}, M> + 'static) -> Self {{\n\ + \x20 let binding = value.into_prop();\n\ + \x20 self.with_op(move |_, control| {{\n\ + \x20 crate::view::apply_prop(control, binding, |c, v| c.set_{builder}(v))\n\ + \x20 }})\n\ + \x20 }}\n" + )); + } + } + } + } + for event in &owner.events { + let event_name = to_snake(&event.name); + let arg_type = if event.payload_kind == "Args" { + let args_name = simple_name( + event + .args_interface_name + .as_deref() + .expect("argsInterfaceName"), + ); + format!("&mut sys::ComPtr") + } else if !event.parameters.is_empty() { + format!("&mut {}", event_arguments_name(event)) + } else { + "()".to_string() + }; + out.push_str(&format!( + " pub fn on_{event_name}(self, callback: impl FnMut({arg_type}) + Send + 'static) -> Self {{\n\ + \x20 self.with_op(move |scope, control| {{\n\ + \x20 scope.retain_subscription(control.subscribe_{event_name}(callback)?);\n\ + \x20 Ok(())\n\ + \x20 }})\n\ + \x20 }}\n" + )); + } + } + + if is_control(ir, ty) { + for property in &ir.attached_properties { + let owner = to_snake(&property.owner_name); + let name = to_snake(&property.name); + let enum_name = simple_name(&property.managed_type_name); + let is_enum = ir + .enums + .iter() + .any(|projected_enum| projected_enum.full_name == property.managed_type_name); + let prop_type = if property.kind == "StringUtf16" { + "String".to_string() + } else if is_enum { + enum_name.to_string() + } else if property.kind == "TimeSpanI64" { + "std::time::Duration".to_string() + } else if let Some(geometry) = geometry::find(&property.kind) { + if property.is_nullable { + format!("Option<{}>", geometry.safe_name) + } else { + geometry.safe_name.to_string() + } + } else { + rust_scalar_kind(&property.kind).to_string() + }; + out.push_str(&format!( + " pub fn {owner}_{name}(self, value: impl crate::view::IntoProp<{prop_type}, M> + 'static) -> Self {{\n\ + \x20 let binding = value.into_prop();\n\ + \x20 self.with_op(move |_, control| {{\n\ + \x20 crate::view::apply_prop(control, binding, |c, v| c.set_{owner}_{name}(v))\n\ + \x20 }})\n\ + \x20 }}\n" + )); + } + } + + if all_props + .iter() + .any(|p| p.kind == "ComCollection" && p.name == "Children") + { + out.push_str( + " pub fn rsx_child(self, value: impl crate::view::IntoChildEl + 'static) -> Self {\n\ + \x20 self.child(value)\n\ + \x20 }\n", + ); + } else if all_props.iter().any(|p| { + p.can_write + && p.kind == "ComInterface" + && p.name == "Content" + && p.interface_name.as_deref().map(simple_name) == Some("IAvnControl") + }) { + out.push_str( + " pub fn rsx_child(self, value: impl crate::view::IntoContentEl + 'static) -> Self {\n\ + \x20 self.content(value)\n\ + \x20 }\n", + ); + } else if all_props.iter().any(|p| { + p.can_write + && p.kind == "ComInterface" + && p.name == "Child" + && p.interface_name.as_deref().map(simple_name) == Some("IAvnControl") + }) { + out.push_str( + " pub fn rsx_child(self, value: impl crate::view::IntoContentEl + 'static) -> Self {\n\ + \x20 self.child(value)\n\ + \x20 }\n", + ); + } else if all_props + .iter() + .any(|p| p.kind == "ComCollection" && p.name == "Items") + { + out.push_str( + " pub fn rsx_child(self, value: impl crate::view::IntoChildEl + 'static) -> Self {\n\ + \x20 self.item(value)\n\ + \x20 }\n", + ); + } else if all_props + .iter() + .any(|p| p.can_write && p.kind == "StringUtf16" && p.name == "Text") + { + out.push_str( + " pub fn rsx_child(self, value: impl crate::view::IntoProp + 'static) -> Self {\n\ + \x20 self.text(value)\n\ + \x20 }\n", + ); + } + + out.push_str("}\n"); + out +} + fn emit_property( property: &ProjectedProperty, reserved_methods: &std::collections::HashSet, @@ -1178,15 +1746,15 @@ fn safe_property_input( if let Some(geometry) = geometry::find(&property.kind) { if property.is_nullable { return ( - format!("Option<{}>", geometry.safe_name), + format!("impl Into>", geometry.safe_name), String::new(), - format!("{}::to_optional_abi(value)", geometry.safe_name), + format!("{}::to_optional_abi(value.into())", geometry.safe_name), ); } return ( - geometry.safe_name.into(), + format!("impl Into<{}>", geometry.safe_name), String::new(), - "value.into()".into(), + "value.into().into()".into(), ); } match property.kind.as_str() { @@ -1287,8 +1855,8 @@ fn safe_property_input( "value".into(), ), "PixelPointI32" => ( - "PixelPoint".into(), - " let value = value.to_abi();\n".into(), + "impl Into".into(), + " let value = value.into().to_abi();\n".into(), "value".into(), ), "I32" if is_enum_property(property, flags_enums) => ( diff --git a/rust/rustolonia-bindgen/src/geometry.rs b/rust/rustolonia-bindgen/src/geometry.rs index fd076b4..be4056f 100644 --- a/rust/rustolonia-bindgen/src/geometry.rs +++ b/rust/rustolonia-bindgen/src/geometry.rs @@ -314,10 +314,126 @@ pub fn emit_safe_structs() -> String { \x20 /// A fully opaque colour.\n\ \x20 pub const fn rgb(r: u8, g: u8, b: u8) -> Self {{\n\ \x20 Self::new(255, r, g, b)\n\ + \x20 }}\n\n\ + \x20 /// Parses `#RGB`, `#ARGB`, `#RRGGBB`, or `#AARRGGBB` (leading `#` optional).\n\ + \x20 pub fn parse_hex(hex: &str) -> Option {{\n\ + \x20 let hex = hex.strip_prefix('#').unwrap_or(hex);\n\ + \x20 if !hex.is_ascii() {{\n\ + \x20 return None;\n\ + \x20 }}\n\ + \x20 match hex.len() {{\n\ + \x20 3 => {{\n\ + \x20 let r = u8::from_str_radix(&hex[0..1], 16).ok()? * 17;\n\ + \x20 let g = u8::from_str_radix(&hex[1..2], 16).ok()? * 17;\n\ + \x20 let b = u8::from_str_radix(&hex[2..3], 16).ok()? * 17;\n\ + \x20 Some(Self::rgb(r, g, b))\n\ + \x20 }}\n\ + \x20 4 => {{\n\ + \x20 let a = u8::from_str_radix(&hex[0..1], 16).ok()? * 17;\n\ + \x20 let r = u8::from_str_radix(&hex[1..2], 16).ok()? * 17;\n\ + \x20 let g = u8::from_str_radix(&hex[2..3], 16).ok()? * 17;\n\ + \x20 let b = u8::from_str_radix(&hex[3..4], 16).ok()? * 17;\n\ + \x20 Some(Self::new(a, r, g, b))\n\ + \x20 }}\n\ + \x20 6 => {{\n\ + \x20 let r = u8::from_str_radix(&hex[0..2], 16).ok()?;\n\ + \x20 let g = u8::from_str_radix(&hex[2..4], 16).ok()?;\n\ + \x20 let b = u8::from_str_radix(&hex[4..6], 16).ok()?;\n\ + \x20 Some(Self::rgb(r, g, b))\n\ + \x20 }}\n\ + \x20 8 => {{\n\ + \x20 let a = u8::from_str_radix(&hex[0..2], 16).ok()?;\n\ + \x20 let r = u8::from_str_radix(&hex[2..4], 16).ok()?;\n\ + \x20 let g = u8::from_str_radix(&hex[4..6], 16).ok()?;\n\ + \x20 let b = u8::from_str_radix(&hex[6..8], 16).ok()?;\n\ + \x20 Some(Self::new(a, r, g, b))\n\ + \x20 }}\n\ + \x20 _ => None,\n\ + \x20 }}\n\ + \x20 }}\n\ + }}\n\n\ + impl From<(u8, u8, u8)> for {safe} {{\n\ + \x20 fn from((r, g, b): (u8, u8, u8)) -> Self {{\n\ + \x20 Self::rgb(r, g, b)\n\ + \x20 }}\n\ + }}\n\n\ + impl From<(u8, u8, u8, u8)> for {safe} {{\n\ + \x20 fn from((a, r, g, b): (u8, u8, u8, u8)) -> Self {{\n\ + \x20 Self::new(a, r, g, b)\n\ + \x20 }}\n\ + }}\n\n\ + impl From for {safe} {{\n\ + \x20 fn from(argb: u32) -> Self {{\n\ + \x20 Self::new(\n\ + \x20 (argb >> 24) as u8,\n\ + \x20 (argb >> 16) as u8,\n\ + \x20 (argb >> 8) as u8,\n\ + \x20 argb as u8,\n\ + \x20 )\n\ + \x20 }}\n\ + }}\n\n" + )); + } + + if geometry.helpers.contains(&Helper::Uniform) { + out.push_str(&format!( + "impl From for {safe} {{\n\ + \x20 fn from(value: f64) -> Self {{\n\ + \x20 Self::uniform(value)\n\ + \x20 }}\n\ + }}\n\n" + )); + } + if geometry + .helpers + .iter() + .any(|helper| matches!(helper, Helper::Symmetric(_))) + { + out.push_str(&format!( + "impl From<(f64, f64)> for {safe} {{\n\ + \x20 fn from((horizontal, vertical): (f64, f64)) -> Self {{\n\ + \x20 Self::symmetric(horizontal, vertical)\n\ + \x20 }}\n\ + }}\n\n" + )); + } + if geometry.conversion == Conversion::Components && geometry.fields.len() == 2 { + out.push_str(&format!( + "impl From<(f64, f64)> for {safe} {{\n\ + \x20 fn from((a, b): (f64, f64)) -> Self {{\n\ + \x20 Self::new(a, b)\n\ + \x20 }}\n\ + }}\n\n\ + impl From<[f64; 2]> for {safe} {{\n\ + \x20 fn from([a, b]: [f64; 2]) -> Self {{\n\ + \x20 Self::new(a, b)\n\ \x20 }}\n\ }}\n\n" )); } + if geometry.conversion == Conversion::Components && geometry.fields.len() == 4 { + out.push_str(&format!( + "impl From<(f64, f64, f64, f64)> for {safe} {{\n\ + \x20 fn from((a, b, c, d): (f64, f64, f64, f64)) -> Self {{\n\ + \x20 Self::new(a, b, c, d)\n\ + \x20 }}\n\ + }}\n\n\ + impl From<[f64; 4]> for {safe} {{\n\ + \x20 fn from([a, b, c, d]: [f64; 4]) -> Self {{\n\ + \x20 Self::new(a, b, c, d)\n\ + \x20 }}\n\ + }}\n\n" + )); + } + if geometry.kind == "Rect" { + out.push_str( + "impl From<(Point, Size)> for Rect {\n\ + \x20 fn from((origin, size): (Point, Size)) -> Self {\n\ + \x20 Self::new(origin.x, origin.y, size.width, size.height)\n\ + \x20 }\n\ + }\n\n", + ); + } match geometry.conversion { Conversion::Components => { diff --git a/rust/rustolonia-sys/src/com.rs b/rust/rustolonia-sys/src/com.rs index 60d0689..d88528b 100644 --- a/rust/rustolonia-sys/src/com.rs +++ b/rust/rustolonia-sys/src/com.rs @@ -38,6 +38,7 @@ unsafe impl ComInterface for IUnknown { const IID: Guid = Guid::IUNKNOWN; } +#[repr(C)] pub struct ComPtr { ptr: NonNull, lifetime: Option>, @@ -106,6 +107,28 @@ impl ComPtr { self.query_interface::() } + /// Reinterprets a borrowed `ComPtr` as `&ComPtr` when `T`'s vtable starts + /// with `U`'s vtable. + /// + /// # Safety + /// `T` must be a single-inheritance subtype of `U` with a prefix-compatible vtable. + pub unsafe fn cast_ref(&self) -> &ComPtr { + unsafe { &*(self as *const ComPtr as *const ComPtr) } + } + + /// Clones this pointer and reinterprets it as `ComPtr` without an FFI `QueryInterface` call. + /// + /// # Safety + /// `T` must be a single-inheritance subtype of `U` with a prefix-compatible vtable. + pub unsafe fn cast_clone(&self) -> ComPtr { + self.add_ref(); + ComPtr { + ptr: self.ptr.cast(), + lifetime: self.clone_lifetime(), + _marker: PhantomData, + } + } + fn clone_lifetime(&self) -> Option> { self.lifetime.inspect(|lifetime| unsafe { let unknown = lifetime.as_ptr(); diff --git a/rust/rustolonia/src/.rustolonia-bindgen.owned.json b/rust/rustolonia/src/.rustolonia-bindgen.owned.json index f23d48a..644d035 100644 --- a/rust/rustolonia/src/.rustolonia-bindgen.owned.json +++ b/rust/rustolonia/src/.rustolonia-bindgen.owned.json @@ -3,7 +3,7 @@ "files": [ { "path": "generated.rs", - "sha256": "d1bc058c9d2e78336025223b90c3c74d484e7b9c1c73155121953f7bac740666" + "sha256": "4ba9beddbbe5943d37a0f2b3bc75baa6ccc13ec8aa969a7961048e61ac21b297" } ] } diff --git a/rust/rustolonia/src/generated.rs b/rust/rustolonia/src/generated.rs index 221b2e4..81b1e9f 100644 --- a/rust/rustolonia/src/generated.rs +++ b/rust/rustolonia/src/generated.rs @@ -40,6 +40,30 @@ impl Thickness { } } +impl From for Thickness { + fn from(value: f64) -> Self { + Self::uniform(value) + } +} + +impl From<(f64, f64)> for Thickness { + fn from((horizontal, vertical): (f64, f64)) -> Self { + Self::symmetric(horizontal, vertical) + } +} + +impl From<(f64, f64, f64, f64)> for Thickness { + fn from((a, b, c, d): (f64, f64, f64, f64)) -> Self { + Self::new(a, b, c, d) + } +} + +impl From<[f64; 4]> for Thickness { + fn from([a, b, c, d]: [f64; 4]) -> Self { + Self::new(a, b, c, d) + } +} + impl From for Thickness { fn from(value: sys::AvnThickness) -> Self { Self { @@ -94,6 +118,24 @@ impl CornerRadius { } } +impl From for CornerRadius { + fn from(value: f64) -> Self { + Self::uniform(value) + } +} + +impl From<(f64, f64, f64, f64)> for CornerRadius { + fn from((a, b, c, d): (f64, f64, f64, f64)) -> Self { + Self::new(a, b, c, d) + } +} + +impl From<[f64; 4]> for CornerRadius { + fn from([a, b, c, d]: [f64; 4]) -> Self { + Self::new(a, b, c, d) + } +} + impl From for CornerRadius { fn from(value: sys::AvnCornerRadius) -> Self { Self { @@ -142,6 +184,18 @@ impl Size { } } +impl From<(f64, f64)> for Size { + fn from((a, b): (f64, f64)) -> Self { + Self::new(a, b) + } +} + +impl From<[f64; 2]> for Size { + fn from([a, b]: [f64; 2]) -> Self { + Self::new(a, b) + } +} + impl From for Size { fn from(value: sys::AvnSize) -> Self { Self { @@ -186,6 +240,18 @@ impl Point { } } +impl From<(f64, f64)> for Point { + fn from((a, b): (f64, f64)) -> Self { + Self::new(a, b) + } +} + +impl From<[f64; 2]> for Point { + fn from([a, b]: [f64; 2]) -> Self { + Self::new(a, b) + } +} + impl From for Point { fn from(value: sys::AvnPoint) -> Self { Self { @@ -232,6 +298,24 @@ impl Rect { } } +impl From<(f64, f64, f64, f64)> for Rect { + fn from((a, b, c, d): (f64, f64, f64, f64)) -> Self { + Self::new(a, b, c, d) + } +} + +impl From<[f64; 4]> for Rect { + fn from([a, b, c, d]: [f64; 4]) -> Self { + Self::new(a, b, c, d) + } +} + +impl From<(Point, Size)> for Rect { + fn from((origin, size): (Point, Size)) -> Self { + Self::new(origin.x, origin.y, size.width, size.height) + } +} + impl From for Rect { fn from(value: sys::AvnRect) -> Self { Self { @@ -287,6 +371,66 @@ impl Color { pub const fn rgb(r: u8, g: u8, b: u8) -> Self { Self::new(255, r, g, b) } + + /// Parses `#RGB`, `#ARGB`, `#RRGGBB`, or `#AARRGGBB` (leading `#` optional). + pub fn parse_hex(hex: &str) -> Option { + let hex = hex.strip_prefix('#').unwrap_or(hex); + if !hex.is_ascii() { + return None; + } + match hex.len() { + 3 => { + let r = u8::from_str_radix(&hex[0..1], 16).ok()? * 17; + let g = u8::from_str_radix(&hex[1..2], 16).ok()? * 17; + let b = u8::from_str_radix(&hex[2..3], 16).ok()? * 17; + Some(Self::rgb(r, g, b)) + } + 4 => { + let a = u8::from_str_radix(&hex[0..1], 16).ok()? * 17; + let r = u8::from_str_radix(&hex[1..2], 16).ok()? * 17; + let g = u8::from_str_radix(&hex[2..3], 16).ok()? * 17; + let b = u8::from_str_radix(&hex[3..4], 16).ok()? * 17; + Some(Self::new(a, r, g, b)) + } + 6 => { + let r = u8::from_str_radix(&hex[0..2], 16).ok()?; + let g = u8::from_str_radix(&hex[2..4], 16).ok()?; + let b = u8::from_str_radix(&hex[4..6], 16).ok()?; + Some(Self::rgb(r, g, b)) + } + 8 => { + let a = u8::from_str_radix(&hex[0..2], 16).ok()?; + let r = u8::from_str_radix(&hex[2..4], 16).ok()?; + let g = u8::from_str_radix(&hex[4..6], 16).ok()?; + let b = u8::from_str_radix(&hex[6..8], 16).ok()?; + Some(Self::new(a, r, g, b)) + } + _ => None, + } + } +} + +impl From<(u8, u8, u8)> for Color { + fn from((r, g, b): (u8, u8, u8)) -> Self { + Self::rgb(r, g, b) + } +} + +impl From<(u8, u8, u8, u8)> for Color { + fn from((a, r, g, b): (u8, u8, u8, u8)) -> Self { + Self::new(a, r, g, b) + } +} + +impl From for Color { + fn from(argb: u32) -> Self { + Self::new( + (argb >> 24) as u8, + (argb >> 16) as u8, + (argb >> 8) as u8, + argb as u8, + ) + } } impl From for Color { @@ -337,6 +481,18 @@ impl Vector { } } +impl From<(f64, f64)> for Vector { + fn from((a, b): (f64, f64)) -> Self { + Self::new(a, b) + } +} + +impl From<[f64; 2]> for Vector { + fn from([a, b]: [f64; 2]) -> Self { + Self::new(a, b) + } +} + impl From for Vector { fn from(value: sys::AvnVector) -> Self { Self { @@ -387,6 +543,18 @@ impl PixelPoint { } } +impl From<(i32, i32)> for PixelPoint { + fn from((x, y): (i32, i32)) -> Self { + Self::new(x, y) + } +} + +impl From<[i32; 2]> for PixelPoint { + fn from([x, y]: [i32; 2]) -> Self { + Self::new(x, y) + } +} + /// A command parameter: the closed set an `object` slot can carry. #[derive(Clone, Debug, PartialEq)] pub enum Variant { @@ -533,6 +701,18 @@ impl From for Brush { } } +impl From<(u8, u8, u8)> for Brush { + fn from((r, g, b): (u8, u8, u8)) -> Self { + Self::solid(Color::rgb(r, g, b)) + } +} + +impl From<(u8, u8, u8, u8)> for Brush { + fn from((a, r, g, b): (u8, u8, u8, u8)) -> Self { + Self::solid(Color::new(a, r, g, b)) + } +} + /// Spread behaviour for a gradient outside its `[0, 1]` stop range. /// Mirrors `Avalonia.Media.GradientSpreadMethod`. #[repr(i32)] @@ -819,6 +999,18 @@ impl From for Paint { } } +impl From<(u8, u8, u8)> for Paint { + fn from((r, g, b): (u8, u8, u8)) -> Self { + Self::Solid(Brush::solid(Color::rgb(r, g, b))) + } +} + +impl From<(u8, u8, u8, u8)> for Paint { + fn from((a, r, g, b): (u8, u8, u8, u8)) -> Self { + Self::Solid(Brush::solid(Color::new(a, r, g, b))) + } +} + impl From for Paint { fn from(brush: LinearGradientBrush) -> Self { Self::LinearGradient(brush) @@ -2967,6 +3159,7 @@ impl StringList { pub fn clear(&self) -> Result<()> { Ok(self.raw.clear()?) } } +#[repr(transparent)] #[derive(Clone, Debug)] pub struct AvaloniaObject { pub(crate) raw: sys::ComPtr, @@ -2977,9 +3170,16 @@ impl AvaloniaObject { with_factory(|factory| factory.create_avalonia_object()) .map(|raw| Self { raw }) } + pub fn el() -> crate::view::El { + crate::view::El::new(Self::new) + } } +impl crate::view::El { +} + +#[repr(transparent)] #[derive(Clone, Debug)] pub struct AutoCompleteBox { pub(crate) raw: sys::ComPtr, @@ -2990,6 +3190,9 @@ impl AutoCompleteBox { with_factory(|factory| factory.create_auto_complete_box()) .map(|raw| Self { raw }) } + pub fn el() -> crate::view::El { + crate::view::El::new(Self::new) + } pub fn get_name(&self) -> Result> { unsafe { Ok(sys::take_utf16(self.raw.get_name()?)) } } @@ -3202,10 +3405,10 @@ impl AutoCompleteBox { pub fn get_margin(&self) -> Result { Ok(self.raw.get_margin()?.into()) } - pub fn set_margin(&self, value: Thickness) -> Result<()> { - Ok(self.raw.set_margin(value.into())?) + pub fn set_margin(&self, value: impl Into) -> Result<()> { + Ok(self.raw.set_margin(value.into().into())?) } - pub fn margin(self, value: Thickness) -> Result { + pub fn margin(self, value: impl Into) -> Result { self.set_margin(value)?; Ok(self) } @@ -3424,20 +3627,20 @@ impl AutoCompleteBox { pub fn get_border_thickness(&self) -> Result { Ok(self.raw.get_border_thickness()?.into()) } - pub fn set_border_thickness(&self, value: Thickness) -> Result<()> { - Ok(self.raw.set_border_thickness(value.into())?) + pub fn set_border_thickness(&self, value: impl Into) -> Result<()> { + Ok(self.raw.set_border_thickness(value.into().into())?) } - pub fn border_thickness(self, value: Thickness) -> Result { + pub fn border_thickness(self, value: impl Into) -> Result { self.set_border_thickness(value)?; Ok(self) } pub fn get_corner_radius(&self) -> Result { Ok(self.raw.get_corner_radius()?.into()) } - pub fn set_corner_radius(&self, value: CornerRadius) -> Result<()> { - Ok(self.raw.set_corner_radius(value.into())?) + pub fn set_corner_radius(&self, value: impl Into) -> Result<()> { + Ok(self.raw.set_corner_radius(value.into().into())?) } - pub fn corner_radius(self, value: CornerRadius) -> Result { + pub fn corner_radius(self, value: impl Into) -> Result { self.set_corner_radius(value)?; Ok(self) } @@ -3526,10 +3729,10 @@ impl AutoCompleteBox { pub fn get_padding(&self) -> Result { Ok(self.raw.get_padding()?.into()) } - pub fn set_padding(&self, value: Thickness) -> Result<()> { - Ok(self.raw.set_padding(value.into())?) + pub fn set_padding(&self, value: impl Into) -> Result<()> { + Ok(self.raw.set_padding(value.into().into())?) } - pub fn padding(self, value: Thickness) -> Result { + pub fn padding(self, value: impl Into) -> Result { self.set_padding(value)?; Ok(self) } @@ -3846,6 +4049,331 @@ impl AutoCompleteBox { scope.retain_subscription(self.subscribe_selection_changed(callback)?); Ok(self) } + pub fn get_canvas_left(&self) -> Result { + Canvas::get_left(self) + } + pub fn set_canvas_left(&self, value: f64) -> Result<()> { + Canvas::set_left(self, value) + } + pub fn canvas_left(self, value: f64) -> Result { + Canvas::set_left(&self, value)?; + Ok(self) + } + pub fn get_canvas_top(&self) -> Result { + Canvas::get_top(self) + } + pub fn set_canvas_top(&self, value: f64) -> Result<()> { + Canvas::set_top(self, value) + } + pub fn canvas_top(self, value: f64) -> Result { + Canvas::set_top(&self, value)?; + Ok(self) + } + pub fn get_canvas_right(&self) -> Result { + Canvas::get_right(self) + } + pub fn set_canvas_right(&self, value: f64) -> Result<()> { + Canvas::set_right(self, value) + } + pub fn canvas_right(self, value: f64) -> Result { + Canvas::set_right(&self, value)?; + Ok(self) + } + pub fn get_canvas_bottom(&self) -> Result { + Canvas::get_bottom(self) + } + pub fn set_canvas_bottom(&self, value: f64) -> Result<()> { + Canvas::set_bottom(self, value) + } + pub fn canvas_bottom(self, value: f64) -> Result { + Canvas::set_bottom(&self, value)?; + Ok(self) + } + pub fn get_dock_panel_dock(&self) -> Result { + DockPanel::get_dock(self) + } + pub fn set_dock_panel_dock(&self, value: Dock) -> Result<()> { + DockPanel::set_dock(self, value) + } + pub fn dock_panel_dock(self, value: Dock) -> Result { + DockPanel::set_dock(&self, value)?; + Ok(self) + } + pub fn get_grid_column(&self) -> Result { + Grid::get_column(self) + } + pub fn set_grid_column(&self, value: i32) -> Result<()> { + Grid::set_column(self, value) + } + pub fn grid_column(self, value: i32) -> Result { + Grid::set_column(&self, value)?; + Ok(self) + } + pub fn get_grid_row(&self) -> Result { + Grid::get_row(self) + } + pub fn set_grid_row(&self, value: i32) -> Result<()> { + Grid::set_row(self, value) + } + pub fn grid_row(self, value: i32) -> Result { + Grid::set_row(&self, value)?; + Ok(self) + } + pub fn get_grid_column_span(&self) -> Result { + Grid::get_column_span(self) + } + pub fn set_grid_column_span(&self, value: i32) -> Result<()> { + Grid::set_column_span(self, value) + } + pub fn grid_column_span(self, value: i32) -> Result { + Grid::set_column_span(&self, value)?; + Ok(self) + } + pub fn get_grid_row_span(&self) -> Result { + Grid::get_row_span(self) + } + pub fn set_grid_row_span(&self, value: i32) -> Result<()> { + Grid::set_row_span(self, value) + } + pub fn grid_row_span(self, value: i32) -> Result { + Grid::set_row_span(&self, value)?; + Ok(self) + } + pub fn get_grid_is_shared_size_scope(&self) -> Result { + Grid::get_is_shared_size_scope(self) + } + pub fn set_grid_is_shared_size_scope(&self, value: bool) -> Result<()> { + Grid::set_is_shared_size_scope(self, value) + } + pub fn grid_is_shared_size_scope(self, value: bool) -> Result { + Grid::set_is_shared_size_scope(&self, value)?; + Ok(self) + } + pub fn get_relative_panel_align_left_with_panel(&self) -> Result { + RelativePanel::get_align_left_with_panel(self) + } + pub fn set_relative_panel_align_left_with_panel(&self, value: bool) -> Result<()> { + RelativePanel::set_align_left_with_panel(self, value) + } + pub fn relative_panel_align_left_with_panel(self, value: bool) -> Result { + RelativePanel::set_align_left_with_panel(&self, value)?; + Ok(self) + } + pub fn get_relative_panel_align_right_with_panel(&self) -> Result { + RelativePanel::get_align_right_with_panel(self) + } + pub fn set_relative_panel_align_right_with_panel(&self, value: bool) -> Result<()> { + RelativePanel::set_align_right_with_panel(self, value) + } + pub fn relative_panel_align_right_with_panel(self, value: bool) -> Result { + RelativePanel::set_align_right_with_panel(&self, value)?; + Ok(self) + } + pub fn get_relative_panel_align_top_with_panel(&self) -> Result { + RelativePanel::get_align_top_with_panel(self) + } + pub fn set_relative_panel_align_top_with_panel(&self, value: bool) -> Result<()> { + RelativePanel::set_align_top_with_panel(self, value) + } + pub fn relative_panel_align_top_with_panel(self, value: bool) -> Result { + RelativePanel::set_align_top_with_panel(&self, value)?; + Ok(self) + } + pub fn get_relative_panel_align_bottom_with_panel(&self) -> Result { + RelativePanel::get_align_bottom_with_panel(self) + } + pub fn set_relative_panel_align_bottom_with_panel(&self, value: bool) -> Result<()> { + RelativePanel::set_align_bottom_with_panel(self, value) + } + pub fn relative_panel_align_bottom_with_panel(self, value: bool) -> Result { + RelativePanel::set_align_bottom_with_panel(&self, value)?; + Ok(self) + } + pub fn get_relative_panel_align_horizontal_center_with_panel(&self) -> Result { + RelativePanel::get_align_horizontal_center_with_panel(self) + } + pub fn set_relative_panel_align_horizontal_center_with_panel(&self, value: bool) -> Result<()> { + RelativePanel::set_align_horizontal_center_with_panel(self, value) + } + pub fn relative_panel_align_horizontal_center_with_panel(self, value: bool) -> Result { + RelativePanel::set_align_horizontal_center_with_panel(&self, value)?; + Ok(self) + } + pub fn get_relative_panel_align_vertical_center_with_panel(&self) -> Result { + RelativePanel::get_align_vertical_center_with_panel(self) + } + pub fn set_relative_panel_align_vertical_center_with_panel(&self, value: bool) -> Result<()> { + RelativePanel::set_align_vertical_center_with_panel(self, value) + } + pub fn relative_panel_align_vertical_center_with_panel(self, value: bool) -> Result { + RelativePanel::set_align_vertical_center_with_panel(&self, value)?; + Ok(self) + } + pub fn get_tool_tip_tip(&self) -> Result> { + ToolTip::get_tip(self) + } + pub fn set_tool_tip_tip(&self, value: impl AsRef) -> Result<()> { + ToolTip::set_tip(self, value) + } + pub fn tool_tip_tip(self, value: impl AsRef) -> Result { + ToolTip::set_tip(&self, value)?; + Ok(self) + } + pub fn get_tool_tip_is_open(&self) -> Result { + ToolTip::get_is_open(self) + } + pub fn set_tool_tip_is_open(&self, value: bool) -> Result<()> { + ToolTip::set_is_open(self, value) + } + pub fn tool_tip_is_open(self, value: bool) -> Result { + ToolTip::set_is_open(&self, value)?; + Ok(self) + } + pub fn get_tool_tip_placement(&self) -> Result { + ToolTip::get_placement(self) + } + pub fn set_tool_tip_placement(&self, value: PlacementMode) -> Result<()> { + ToolTip::set_placement(self, value) + } + pub fn tool_tip_placement(self, value: PlacementMode) -> Result { + ToolTip::set_placement(&self, value)?; + Ok(self) + } + pub fn get_tool_tip_horizontal_offset(&self) -> Result { + ToolTip::get_horizontal_offset(self) + } + pub fn set_tool_tip_horizontal_offset(&self, value: f64) -> Result<()> { + ToolTip::set_horizontal_offset(self, value) + } + pub fn tool_tip_horizontal_offset(self, value: f64) -> Result { + ToolTip::set_horizontal_offset(&self, value)?; + Ok(self) + } + pub fn get_tool_tip_vertical_offset(&self) -> Result { + ToolTip::get_vertical_offset(self) + } + pub fn set_tool_tip_vertical_offset(&self, value: f64) -> Result<()> { + ToolTip::set_vertical_offset(self, value) + } + pub fn tool_tip_vertical_offset(self, value: f64) -> Result { + ToolTip::set_vertical_offset(&self, value)?; + Ok(self) + } + pub fn get_tool_tip_show_delay(&self) -> Result { + ToolTip::get_show_delay(self) + } + pub fn set_tool_tip_show_delay(&self, value: i32) -> Result<()> { + ToolTip::set_show_delay(self, value) + } + pub fn tool_tip_show_delay(self, value: i32) -> Result { + ToolTip::set_show_delay(&self, value)?; + Ok(self) + } + pub fn get_tool_tip_between_show_delay(&self) -> Result { + ToolTip::get_between_show_delay(self) + } + pub fn set_tool_tip_between_show_delay(&self, value: i32) -> Result<()> { + ToolTip::set_between_show_delay(self, value) + } + pub fn tool_tip_between_show_delay(self, value: i32) -> Result { + ToolTip::set_between_show_delay(&self, value)?; + Ok(self) + } + pub fn get_tool_tip_show_on_disabled(&self) -> Result { + ToolTip::get_show_on_disabled(self) + } + pub fn set_tool_tip_show_on_disabled(&self, value: bool) -> Result<()> { + ToolTip::set_show_on_disabled(self, value) + } + pub fn tool_tip_show_on_disabled(self, value: bool) -> Result { + ToolTip::set_show_on_disabled(&self, value)?; + Ok(self) + } + pub fn get_tool_tip_service_enabled(&self) -> Result { + ToolTip::get_service_enabled(self) + } + pub fn set_tool_tip_service_enabled(&self, value: bool) -> Result<()> { + ToolTip::set_service_enabled(self, value) + } + pub fn tool_tip_service_enabled(self, value: bool) -> Result { + ToolTip::set_service_enabled(&self, value)?; + Ok(self) + } +} + +impl std::ops::Deref for AutoCompleteBox { + type Target = TemplatedControl; + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Self as *const Self::Target) } + } +} + +unsafe impl crate::Upcast for AutoCompleteBox { + fn upcast(&self) -> AvaloniaObject { + AvaloniaObject { + raw: unsafe { self.raw.cast_clone() }, + } + } + fn upcast_ref(&self) -> &AvaloniaObject { + unsafe { &*(self as *const Self as *const AvaloniaObject) } + } +} + +impl AsRef for AutoCompleteBox { + fn as_ref(&self) -> &AvaloniaObject { + >::upcast_ref(self) + } +} + +unsafe impl crate::Upcast for AutoCompleteBox { + fn upcast(&self) -> StyledElement { + StyledElement { + raw: unsafe { self.raw.cast_clone() }, + } + } + fn upcast_ref(&self) -> &StyledElement { + unsafe { &*(self as *const Self as *const StyledElement) } + } +} + +impl AsRef for AutoCompleteBox { + fn as_ref(&self) -> &StyledElement { + >::upcast_ref(self) + } +} + +unsafe impl crate::Upcast for AutoCompleteBox { + fn upcast(&self) -> Control { + Control { + raw: unsafe { self.raw.cast_clone() }, + } + } + fn upcast_ref(&self) -> &Control { + unsafe { &*(self as *const Self as *const Control) } + } +} + +impl AsRef for AutoCompleteBox { + fn as_ref(&self) -> &Control { + >::upcast_ref(self) + } +} + +unsafe impl crate::Upcast for AutoCompleteBox { + fn upcast(&self) -> TemplatedControl { + TemplatedControl { + raw: unsafe { self.raw.cast_clone() }, + } + } + fn upcast_ref(&self) -> &TemplatedControl { + unsafe { &*(self as *const Self as *const TemplatedControl) } + } +} + +impl AsRef for AutoCompleteBox { + fn as_ref(&self) -> &TemplatedControl { + >::upcast_ref(self) + } } impl AsControl for AutoCompleteBox { @@ -3854,6 +4382,620 @@ impl AsControl for AutoCompleteBox { } } +impl crate::view::El { + pub fn name(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_name(v)) + }) + } + pub fn data_context(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_data_context(v)) + }) + } + pub fn on_attached_to_logical_tree(self, callback: impl FnMut(()) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_attached_to_logical_tree(callback)?); + Ok(()) + }) + } + pub fn on_detached_from_logical_tree(self, callback: impl FnMut(()) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_detached_from_logical_tree(callback)?); + Ok(()) + }) + } + pub fn on_data_context_changed(self, callback: impl FnMut(()) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_data_context_changed(callback)?); + Ok(()) + }) + } + pub fn on_initialized(self, callback: impl FnMut(()) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_initialized(callback)?); + Ok(()) + }) + } + pub fn on_resources_changed(self, callback: impl FnMut(()) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_resources_changed(callback)?); + Ok(()) + }) + } + pub fn on_actual_theme_variant_changed(self, callback: impl FnMut(()) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_actual_theme_variant_changed(callback)?); + Ok(()) + }) + } + pub fn visible(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_visible(v)) + }) + } + pub fn opacity(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_opacity(v)) + }) + } + pub fn context_menu(self, value: Option) -> Self { + self.with_op(move |_, control| control.set_context_menu(value.as_ref())) + } + pub fn context_flyout(self, value: Option) -> Self { + self.with_op(move |_, control| control.set_context_flyout(value.as_ref())) + } + pub fn tag(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_tag(v)) + }) + } + pub fn width(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_width(v)) + }) + } + pub fn height(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_height(v)) + }) + } + pub fn min_width(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_min_width(v)) + }) + } + pub fn max_width(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_max_width(v)) + }) + } + pub fn min_height(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_min_height(v)) + }) + } + pub fn max_height(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_max_height(v)) + }) + } + pub fn margin(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_margin(v)) + }) + } + pub fn horizontal_alignment(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_horizontal_alignment(v)) + }) + } + pub fn vertical_alignment(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_vertical_alignment(v)) + }) + } + pub fn focusable(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_focusable(v)) + }) + } + pub fn enabled(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_enabled(v)) + }) + } + pub fn on_loaded(self, callback: impl FnMut(()) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_loaded(callback)?); + Ok(()) + }) + } + pub fn on_unloaded(self, callback: impl FnMut(()) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_unloaded(callback)?); + Ok(()) + }) + } + pub fn on_size_changed(self, callback: impl FnMut(&mut ControlSizeChangedEventArgs) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_size_changed(callback)?); + Ok(()) + }) + } + pub fn on_got_focus(self, callback: impl FnMut(&mut ControlGotFocusEventArgs) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_got_focus(callback)?); + Ok(()) + }) + } + pub fn on_lost_focus(self, callback: impl FnMut(()) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_lost_focus(callback)?); + Ok(()) + }) + } + pub fn on_key_down(self, callback: impl FnMut(&mut ControlKeyDownEventArgs) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_key_down(callback)?); + Ok(()) + }) + } + pub fn on_key_up(self, callback: impl FnMut(&mut ControlKeyUpEventArgs) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_key_up(callback)?); + Ok(()) + }) + } + pub fn on_pointer_entered(self, callback: impl FnMut(&mut ControlPointerEnteredEventArgs) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_pointer_entered(callback)?); + Ok(()) + }) + } + pub fn on_pointer_exited(self, callback: impl FnMut(&mut ControlPointerExitedEventArgs) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_pointer_exited(callback)?); + Ok(()) + }) + } + pub fn on_pointer_wheel_changed(self, callback: impl FnMut(&mut ControlPointerWheelChangedEventArgs) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_pointer_wheel_changed(callback)?); + Ok(()) + }) + } + pub fn on_tapped(self, callback: impl FnMut(&mut ControlTappedEventArgs) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_tapped(callback)?); + Ok(()) + }) + } + pub fn on_double_tapped(self, callback: impl FnMut(()) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_double_tapped(callback)?); + Ok(()) + }) + } + pub fn background(self, value: impl crate::view::IntoProp, M> + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_background(v)) + }) + } + pub fn background_sizing(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_background_sizing(v)) + }) + } + pub fn border_brush(self, value: impl crate::view::IntoProp, M> + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_border_brush(v)) + }) + } + pub fn border_thickness(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_border_thickness(v)) + }) + } + pub fn corner_radius(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_corner_radius(v)) + }) + } + pub fn font_family(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_font_family(v)) + }) + } + pub fn font_features(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_font_features(v)) + }) + } + pub fn font_size(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_font_size(v)) + }) + } + pub fn font_style(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_font_style(v)) + }) + } + pub fn font_weight(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_font_weight(v)) + }) + } + pub fn font_stretch(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_font_stretch(v)) + }) + } + pub fn foreground(self, value: impl crate::view::IntoProp, M> + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_foreground(v)) + }) + } + pub fn letter_spacing(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_letter_spacing(v)) + }) + } + pub fn padding(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_padding(v)) + }) + } + pub fn caret_index(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_caret_index(v)) + }) + } + pub fn minimum_prefix_length(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_minimum_prefix_length(v)) + }) + } + pub fn text_completion_enabled(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_text_completion_enabled(v)) + }) + } + pub fn item_template(self, value: Option) -> Self { + self.with_op(move |_, control| control.set_item_template(value.as_ref())) + } + pub fn minimum_populate_delay(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_minimum_populate_delay(v)) + }) + } + pub fn max_drop_down_height(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_max_drop_down_height(v)) + }) + } + pub fn drop_down_open(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_drop_down_open(v)) + }) + } + pub fn clear_selection_on_lost_focus(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_clear_selection_on_lost_focus(v)) + }) + } + pub fn selected_item(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_selected_item(v)) + }) + } + pub fn text(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |scope, control| { + crate::view::apply_two_way_prop( + scope, + control, + binding, + |c, v| c.set_text(v), + |c: &_| c.get_text().map(|v| v.unwrap_or_default()), + |c, mut cb| c.subscribe_text_changed(move |_| cb()), + ) + }) + } + pub fn filter_mode(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_filter_mode(v)) + }) + } + pub fn placeholder_text(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_placeholder_text(v)) + }) + } + pub fn placeholder_foreground(self, value: impl crate::view::IntoProp, M> + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_placeholder_foreground(v)) + }) + } + pub fn item_filter(self, value: Option>) -> Self { + self.with_op(move |_, control| control.set_item_filter(value.as_ref())) + } + pub fn text_filter(self, value: Option>) -> Self { + self.with_op(move |_, control| control.set_text_filter(value.as_ref())) + } + pub fn item_selector(self, value: Option>) -> Self { + self.with_op(move |_, control| control.set_item_selector(value.as_ref())) + } + pub fn text_selector(self, value: Option>) -> Self { + self.with_op(move |_, control| control.set_text_selector(value.as_ref())) + } + pub fn async_populator(self, value: Option>) -> Self { + self.with_op(move |_, control| control.set_async_populator(value.as_ref())) + } + pub fn max_length(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_max_length(v)) + }) + } + pub fn inner_left_content(self, value: impl crate::view::IntoContentEl + 'static) -> Self { + self.with_op(move |scope, control| { + let built = value.into_content_el().map(|el| el.build(scope)).transpose()?; + control.set_inner_left_content(built.as_ref().map(|c| c as &dyn AsControl)) + }) + } + pub fn inner_right_content(self, value: impl crate::view::IntoContentEl + 'static) -> Self { + self.with_op(move |scope, control| { + let built = value.into_content_el().map(|el| el.build(scope)).transpose()?; + control.set_inner_right_content(built.as_ref().map(|c| c as &dyn AsControl)) + }) + } + pub fn on_text_changed(self, callback: impl FnMut(()) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_text_changed(callback)?); + Ok(()) + }) + } + pub fn on_populating(self, callback: impl FnMut(&mut AutoCompleteBoxPopulatingEventArgs) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_populating(callback)?); + Ok(()) + }) + } + pub fn on_populated(self, callback: impl FnMut(&mut sys::ComPtr) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_populated(callback)?); + Ok(()) + }) + } + pub fn on_drop_down_opening(self, callback: impl FnMut(&mut AutoCompleteBoxDropDownOpeningEventArgs) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_drop_down_opening(callback)?); + Ok(()) + }) + } + pub fn on_drop_down_opened(self, callback: impl FnMut(()) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_drop_down_opened(callback)?); + Ok(()) + }) + } + pub fn on_drop_down_closing(self, callback: impl FnMut(&mut AutoCompleteBoxDropDownClosingEventArgs) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_drop_down_closing(callback)?); + Ok(()) + }) + } + pub fn on_drop_down_closed(self, callback: impl FnMut(()) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_drop_down_closed(callback)?); + Ok(()) + }) + } + pub fn on_selection_changed(self, callback: impl FnMut(&mut sys::ComPtr) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_selection_changed(callback)?); + Ok(()) + }) + } + pub fn canvas_left(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_canvas_left(v)) + }) + } + pub fn canvas_top(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_canvas_top(v)) + }) + } + pub fn canvas_right(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_canvas_right(v)) + }) + } + pub fn canvas_bottom(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_canvas_bottom(v)) + }) + } + pub fn dock_panel_dock(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_dock_panel_dock(v)) + }) + } + pub fn grid_column(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_grid_column(v)) + }) + } + pub fn grid_row(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_grid_row(v)) + }) + } + pub fn grid_column_span(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_grid_column_span(v)) + }) + } + pub fn grid_row_span(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_grid_row_span(v)) + }) + } + pub fn grid_is_shared_size_scope(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_grid_is_shared_size_scope(v)) + }) + } + pub fn relative_panel_align_left_with_panel(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_relative_panel_align_left_with_panel(v)) + }) + } + pub fn relative_panel_align_right_with_panel(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_relative_panel_align_right_with_panel(v)) + }) + } + pub fn relative_panel_align_top_with_panel(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_relative_panel_align_top_with_panel(v)) + }) + } + pub fn relative_panel_align_bottom_with_panel(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_relative_panel_align_bottom_with_panel(v)) + }) + } + pub fn relative_panel_align_horizontal_center_with_panel(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_relative_panel_align_horizontal_center_with_panel(v)) + }) + } + pub fn relative_panel_align_vertical_center_with_panel(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_relative_panel_align_vertical_center_with_panel(v)) + }) + } + pub fn tool_tip_tip(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_tool_tip_tip(v)) + }) + } + pub fn tool_tip_is_open(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_tool_tip_is_open(v)) + }) + } + pub fn tool_tip_placement(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_tool_tip_placement(v)) + }) + } + pub fn tool_tip_horizontal_offset(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_tool_tip_horizontal_offset(v)) + }) + } + pub fn tool_tip_vertical_offset(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_tool_tip_vertical_offset(v)) + }) + } + pub fn tool_tip_show_delay(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_tool_tip_show_delay(v)) + }) + } + pub fn tool_tip_between_show_delay(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_tool_tip_between_show_delay(v)) + }) + } + pub fn tool_tip_show_on_disabled(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_tool_tip_show_on_disabled(v)) + }) + } + pub fn tool_tip_service_enabled(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_tool_tip_service_enabled(v)) + }) + } + pub fn rsx_child(self, value: impl crate::view::IntoProp + 'static) -> Self { + self.text(value) + } +} + +#[repr(transparent)] #[derive(Clone, Debug)] pub struct Border { pub(crate) raw: sys::ComPtr, @@ -3864,6 +5006,9 @@ impl Border { with_factory(|factory| factory.create_border()) .map(|raw| Self { raw }) } + pub fn el() -> crate::view::El { + crate::view::El::new(Self::new) + } pub fn get_name(&self) -> Result> { unsafe { Ok(sys::take_utf16(self.raw.get_name()?)) } } @@ -4076,10 +5221,10 @@ impl Border { pub fn get_margin(&self) -> Result { Ok(self.raw.get_margin()?.into()) } - pub fn set_margin(&self, value: Thickness) -> Result<()> { - Ok(self.raw.set_margin(value.into())?) + pub fn set_margin(&self, value: impl Into) -> Result<()> { + Ok(self.raw.set_margin(value.into().into())?) } - pub fn margin(self, value: Thickness) -> Result { + pub fn margin(self, value: impl Into) -> Result { self.set_margin(value)?; Ok(self) } @@ -4276,10 +5421,10 @@ impl Border { pub fn get_padding(&self) -> Result { Ok(self.raw.get_padding()?.into()) } - pub fn set_padding(&self, value: Thickness) -> Result<()> { - Ok(self.raw.set_padding(value.into())?) + pub fn set_padding(&self, value: impl Into) -> Result<()> { + Ok(self.raw.set_padding(value.into().into())?) } - pub fn padding(self, value: Thickness) -> Result { + pub fn padding(self, value: impl Into) -> Result { self.set_padding(value)?; Ok(self) } @@ -4319,20 +5464,20 @@ impl Border { pub fn get_border_thickness(&self) -> Result { Ok(self.raw.get_border_thickness()?.into()) } - pub fn set_border_thickness(&self, value: Thickness) -> Result<()> { - Ok(self.raw.set_border_thickness(value.into())?) + pub fn set_border_thickness(&self, value: impl Into) -> Result<()> { + Ok(self.raw.set_border_thickness(value.into().into())?) } - pub fn border_thickness(self, value: Thickness) -> Result { + pub fn border_thickness(self, value: impl Into) -> Result { self.set_border_thickness(value)?; Ok(self) } pub fn get_corner_radius(&self) -> Result { Ok(self.raw.get_corner_radius()?.into()) } - pub fn set_corner_radius(&self, value: CornerRadius) -> Result<()> { - Ok(self.raw.set_corner_radius(value.into())?) + pub fn set_corner_radius(&self, value: impl Into) -> Result<()> { + Ok(self.raw.set_corner_radius(value.into().into())?) } - pub fn corner_radius(self, value: CornerRadius) -> Result { + pub fn corner_radius(self, value: impl Into) -> Result { self.set_corner_radius(value)?; Ok(self) } @@ -4350,6 +5495,331 @@ impl Border { pub fn clip_to_bounds_radius(&self) -> Result { Ok(self.raw.get_clip_to_bounds_radius()?.into()) } + pub fn get_canvas_left(&self) -> Result { + Canvas::get_left(self) + } + pub fn set_canvas_left(&self, value: f64) -> Result<()> { + Canvas::set_left(self, value) + } + pub fn canvas_left(self, value: f64) -> Result { + Canvas::set_left(&self, value)?; + Ok(self) + } + pub fn get_canvas_top(&self) -> Result { + Canvas::get_top(self) + } + pub fn set_canvas_top(&self, value: f64) -> Result<()> { + Canvas::set_top(self, value) + } + pub fn canvas_top(self, value: f64) -> Result { + Canvas::set_top(&self, value)?; + Ok(self) + } + pub fn get_canvas_right(&self) -> Result { + Canvas::get_right(self) + } + pub fn set_canvas_right(&self, value: f64) -> Result<()> { + Canvas::set_right(self, value) + } + pub fn canvas_right(self, value: f64) -> Result { + Canvas::set_right(&self, value)?; + Ok(self) + } + pub fn get_canvas_bottom(&self) -> Result { + Canvas::get_bottom(self) + } + pub fn set_canvas_bottom(&self, value: f64) -> Result<()> { + Canvas::set_bottom(self, value) + } + pub fn canvas_bottom(self, value: f64) -> Result { + Canvas::set_bottom(&self, value)?; + Ok(self) + } + pub fn get_dock_panel_dock(&self) -> Result { + DockPanel::get_dock(self) + } + pub fn set_dock_panel_dock(&self, value: Dock) -> Result<()> { + DockPanel::set_dock(self, value) + } + pub fn dock_panel_dock(self, value: Dock) -> Result { + DockPanel::set_dock(&self, value)?; + Ok(self) + } + pub fn get_grid_column(&self) -> Result { + Grid::get_column(self) + } + pub fn set_grid_column(&self, value: i32) -> Result<()> { + Grid::set_column(self, value) + } + pub fn grid_column(self, value: i32) -> Result { + Grid::set_column(&self, value)?; + Ok(self) + } + pub fn get_grid_row(&self) -> Result { + Grid::get_row(self) + } + pub fn set_grid_row(&self, value: i32) -> Result<()> { + Grid::set_row(self, value) + } + pub fn grid_row(self, value: i32) -> Result { + Grid::set_row(&self, value)?; + Ok(self) + } + pub fn get_grid_column_span(&self) -> Result { + Grid::get_column_span(self) + } + pub fn set_grid_column_span(&self, value: i32) -> Result<()> { + Grid::set_column_span(self, value) + } + pub fn grid_column_span(self, value: i32) -> Result { + Grid::set_column_span(&self, value)?; + Ok(self) + } + pub fn get_grid_row_span(&self) -> Result { + Grid::get_row_span(self) + } + pub fn set_grid_row_span(&self, value: i32) -> Result<()> { + Grid::set_row_span(self, value) + } + pub fn grid_row_span(self, value: i32) -> Result { + Grid::set_row_span(&self, value)?; + Ok(self) + } + pub fn get_grid_is_shared_size_scope(&self) -> Result { + Grid::get_is_shared_size_scope(self) + } + pub fn set_grid_is_shared_size_scope(&self, value: bool) -> Result<()> { + Grid::set_is_shared_size_scope(self, value) + } + pub fn grid_is_shared_size_scope(self, value: bool) -> Result { + Grid::set_is_shared_size_scope(&self, value)?; + Ok(self) + } + pub fn get_relative_panel_align_left_with_panel(&self) -> Result { + RelativePanel::get_align_left_with_panel(self) + } + pub fn set_relative_panel_align_left_with_panel(&self, value: bool) -> Result<()> { + RelativePanel::set_align_left_with_panel(self, value) + } + pub fn relative_panel_align_left_with_panel(self, value: bool) -> Result { + RelativePanel::set_align_left_with_panel(&self, value)?; + Ok(self) + } + pub fn get_relative_panel_align_right_with_panel(&self) -> Result { + RelativePanel::get_align_right_with_panel(self) + } + pub fn set_relative_panel_align_right_with_panel(&self, value: bool) -> Result<()> { + RelativePanel::set_align_right_with_panel(self, value) + } + pub fn relative_panel_align_right_with_panel(self, value: bool) -> Result { + RelativePanel::set_align_right_with_panel(&self, value)?; + Ok(self) + } + pub fn get_relative_panel_align_top_with_panel(&self) -> Result { + RelativePanel::get_align_top_with_panel(self) + } + pub fn set_relative_panel_align_top_with_panel(&self, value: bool) -> Result<()> { + RelativePanel::set_align_top_with_panel(self, value) + } + pub fn relative_panel_align_top_with_panel(self, value: bool) -> Result { + RelativePanel::set_align_top_with_panel(&self, value)?; + Ok(self) + } + pub fn get_relative_panel_align_bottom_with_panel(&self) -> Result { + RelativePanel::get_align_bottom_with_panel(self) + } + pub fn set_relative_panel_align_bottom_with_panel(&self, value: bool) -> Result<()> { + RelativePanel::set_align_bottom_with_panel(self, value) + } + pub fn relative_panel_align_bottom_with_panel(self, value: bool) -> Result { + RelativePanel::set_align_bottom_with_panel(&self, value)?; + Ok(self) + } + pub fn get_relative_panel_align_horizontal_center_with_panel(&self) -> Result { + RelativePanel::get_align_horizontal_center_with_panel(self) + } + pub fn set_relative_panel_align_horizontal_center_with_panel(&self, value: bool) -> Result<()> { + RelativePanel::set_align_horizontal_center_with_panel(self, value) + } + pub fn relative_panel_align_horizontal_center_with_panel(self, value: bool) -> Result { + RelativePanel::set_align_horizontal_center_with_panel(&self, value)?; + Ok(self) + } + pub fn get_relative_panel_align_vertical_center_with_panel(&self) -> Result { + RelativePanel::get_align_vertical_center_with_panel(self) + } + pub fn set_relative_panel_align_vertical_center_with_panel(&self, value: bool) -> Result<()> { + RelativePanel::set_align_vertical_center_with_panel(self, value) + } + pub fn relative_panel_align_vertical_center_with_panel(self, value: bool) -> Result { + RelativePanel::set_align_vertical_center_with_panel(&self, value)?; + Ok(self) + } + pub fn get_tool_tip_tip(&self) -> Result> { + ToolTip::get_tip(self) + } + pub fn set_tool_tip_tip(&self, value: impl AsRef) -> Result<()> { + ToolTip::set_tip(self, value) + } + pub fn tool_tip_tip(self, value: impl AsRef) -> Result { + ToolTip::set_tip(&self, value)?; + Ok(self) + } + pub fn get_tool_tip_is_open(&self) -> Result { + ToolTip::get_is_open(self) + } + pub fn set_tool_tip_is_open(&self, value: bool) -> Result<()> { + ToolTip::set_is_open(self, value) + } + pub fn tool_tip_is_open(self, value: bool) -> Result { + ToolTip::set_is_open(&self, value)?; + Ok(self) + } + pub fn get_tool_tip_placement(&self) -> Result { + ToolTip::get_placement(self) + } + pub fn set_tool_tip_placement(&self, value: PlacementMode) -> Result<()> { + ToolTip::set_placement(self, value) + } + pub fn tool_tip_placement(self, value: PlacementMode) -> Result { + ToolTip::set_placement(&self, value)?; + Ok(self) + } + pub fn get_tool_tip_horizontal_offset(&self) -> Result { + ToolTip::get_horizontal_offset(self) + } + pub fn set_tool_tip_horizontal_offset(&self, value: f64) -> Result<()> { + ToolTip::set_horizontal_offset(self, value) + } + pub fn tool_tip_horizontal_offset(self, value: f64) -> Result { + ToolTip::set_horizontal_offset(&self, value)?; + Ok(self) + } + pub fn get_tool_tip_vertical_offset(&self) -> Result { + ToolTip::get_vertical_offset(self) + } + pub fn set_tool_tip_vertical_offset(&self, value: f64) -> Result<()> { + ToolTip::set_vertical_offset(self, value) + } + pub fn tool_tip_vertical_offset(self, value: f64) -> Result { + ToolTip::set_vertical_offset(&self, value)?; + Ok(self) + } + pub fn get_tool_tip_show_delay(&self) -> Result { + ToolTip::get_show_delay(self) + } + pub fn set_tool_tip_show_delay(&self, value: i32) -> Result<()> { + ToolTip::set_show_delay(self, value) + } + pub fn tool_tip_show_delay(self, value: i32) -> Result { + ToolTip::set_show_delay(&self, value)?; + Ok(self) + } + pub fn get_tool_tip_between_show_delay(&self) -> Result { + ToolTip::get_between_show_delay(self) + } + pub fn set_tool_tip_between_show_delay(&self, value: i32) -> Result<()> { + ToolTip::set_between_show_delay(self, value) + } + pub fn tool_tip_between_show_delay(self, value: i32) -> Result { + ToolTip::set_between_show_delay(&self, value)?; + Ok(self) + } + pub fn get_tool_tip_show_on_disabled(&self) -> Result { + ToolTip::get_show_on_disabled(self) + } + pub fn set_tool_tip_show_on_disabled(&self, value: bool) -> Result<()> { + ToolTip::set_show_on_disabled(self, value) + } + pub fn tool_tip_show_on_disabled(self, value: bool) -> Result { + ToolTip::set_show_on_disabled(&self, value)?; + Ok(self) + } + pub fn get_tool_tip_service_enabled(&self) -> Result { + ToolTip::get_service_enabled(self) + } + pub fn set_tool_tip_service_enabled(&self, value: bool) -> Result<()> { + ToolTip::set_service_enabled(self, value) + } + pub fn tool_tip_service_enabled(self, value: bool) -> Result { + ToolTip::set_service_enabled(&self, value)?; + Ok(self) + } +} + +impl std::ops::Deref for Border { + type Target = Decorator; + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Self as *const Self::Target) } + } +} + +unsafe impl crate::Upcast for Border { + fn upcast(&self) -> AvaloniaObject { + AvaloniaObject { + raw: unsafe { self.raw.cast_clone() }, + } + } + fn upcast_ref(&self) -> &AvaloniaObject { + unsafe { &*(self as *const Self as *const AvaloniaObject) } + } +} + +impl AsRef for Border { + fn as_ref(&self) -> &AvaloniaObject { + >::upcast_ref(self) + } +} + +unsafe impl crate::Upcast for Border { + fn upcast(&self) -> StyledElement { + StyledElement { + raw: unsafe { self.raw.cast_clone() }, + } + } + fn upcast_ref(&self) -> &StyledElement { + unsafe { &*(self as *const Self as *const StyledElement) } + } +} + +impl AsRef for Border { + fn as_ref(&self) -> &StyledElement { + >::upcast_ref(self) + } +} + +unsafe impl crate::Upcast for Border { + fn upcast(&self) -> Control { + Control { + raw: unsafe { self.raw.cast_clone() }, + } + } + fn upcast_ref(&self) -> &Control { + unsafe { &*(self as *const Self as *const Control) } + } +} + +impl AsRef for Border { + fn as_ref(&self) -> &Control { + >::upcast_ref(self) + } +} + +unsafe impl crate::Upcast for Border { + fn upcast(&self) -> Decorator { + Decorator { + raw: unsafe { self.raw.cast_clone() }, + } + } + fn upcast_ref(&self) -> &Decorator { + unsafe { &*(self as *const Self as *const Decorator) } + } +} + +impl AsRef for Border { + fn as_ref(&self) -> &Decorator { + >::upcast_ref(self) + } } impl AsControl for Border { @@ -4358,6 +5828,421 @@ impl AsControl for Border { } } +impl crate::view::El { + pub fn name(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_name(v)) + }) + } + pub fn data_context(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_data_context(v)) + }) + } + pub fn on_attached_to_logical_tree(self, callback: impl FnMut(()) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_attached_to_logical_tree(callback)?); + Ok(()) + }) + } + pub fn on_detached_from_logical_tree(self, callback: impl FnMut(()) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_detached_from_logical_tree(callback)?); + Ok(()) + }) + } + pub fn on_data_context_changed(self, callback: impl FnMut(()) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_data_context_changed(callback)?); + Ok(()) + }) + } + pub fn on_initialized(self, callback: impl FnMut(()) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_initialized(callback)?); + Ok(()) + }) + } + pub fn on_resources_changed(self, callback: impl FnMut(()) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_resources_changed(callback)?); + Ok(()) + }) + } + pub fn on_actual_theme_variant_changed(self, callback: impl FnMut(()) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_actual_theme_variant_changed(callback)?); + Ok(()) + }) + } + pub fn visible(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_visible(v)) + }) + } + pub fn opacity(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_opacity(v)) + }) + } + pub fn context_menu(self, value: Option) -> Self { + self.with_op(move |_, control| control.set_context_menu(value.as_ref())) + } + pub fn context_flyout(self, value: Option) -> Self { + self.with_op(move |_, control| control.set_context_flyout(value.as_ref())) + } + pub fn tag(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_tag(v)) + }) + } + pub fn width(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_width(v)) + }) + } + pub fn height(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_height(v)) + }) + } + pub fn min_width(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_min_width(v)) + }) + } + pub fn max_width(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_max_width(v)) + }) + } + pub fn min_height(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_min_height(v)) + }) + } + pub fn max_height(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_max_height(v)) + }) + } + pub fn margin(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_margin(v)) + }) + } + pub fn horizontal_alignment(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_horizontal_alignment(v)) + }) + } + pub fn vertical_alignment(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_vertical_alignment(v)) + }) + } + pub fn focusable(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_focusable(v)) + }) + } + pub fn enabled(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_enabled(v)) + }) + } + pub fn on_loaded(self, callback: impl FnMut(()) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_loaded(callback)?); + Ok(()) + }) + } + pub fn on_unloaded(self, callback: impl FnMut(()) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_unloaded(callback)?); + Ok(()) + }) + } + pub fn on_size_changed(self, callback: impl FnMut(&mut ControlSizeChangedEventArgs) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_size_changed(callback)?); + Ok(()) + }) + } + pub fn on_got_focus(self, callback: impl FnMut(&mut ControlGotFocusEventArgs) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_got_focus(callback)?); + Ok(()) + }) + } + pub fn on_lost_focus(self, callback: impl FnMut(()) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_lost_focus(callback)?); + Ok(()) + }) + } + pub fn on_key_down(self, callback: impl FnMut(&mut ControlKeyDownEventArgs) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_key_down(callback)?); + Ok(()) + }) + } + pub fn on_key_up(self, callback: impl FnMut(&mut ControlKeyUpEventArgs) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_key_up(callback)?); + Ok(()) + }) + } + pub fn on_pointer_entered(self, callback: impl FnMut(&mut ControlPointerEnteredEventArgs) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_pointer_entered(callback)?); + Ok(()) + }) + } + pub fn on_pointer_exited(self, callback: impl FnMut(&mut ControlPointerExitedEventArgs) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_pointer_exited(callback)?); + Ok(()) + }) + } + pub fn on_pointer_wheel_changed(self, callback: impl FnMut(&mut ControlPointerWheelChangedEventArgs) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_pointer_wheel_changed(callback)?); + Ok(()) + }) + } + pub fn on_tapped(self, callback: impl FnMut(&mut ControlTappedEventArgs) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_tapped(callback)?); + Ok(()) + }) + } + pub fn on_double_tapped(self, callback: impl FnMut(()) + Send + 'static) -> Self { + self.with_op(move |scope, control| { + scope.retain_subscription(control.subscribe_double_tapped(callback)?); + Ok(()) + }) + } + pub fn child(self, value: impl crate::view::IntoContentEl + 'static) -> Self { + self.with_op(move |scope, control| { + let built = value.into_content_el().map(|el| el.build(scope)).transpose()?; + control.set_child(built.as_ref().map(|c| c as &dyn AsControl)) + }) + } + pub fn padding(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_padding(v)) + }) + } + pub fn background(self, value: impl crate::view::IntoProp, M> + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_background(v)) + }) + } + pub fn background_sizing(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_background_sizing(v)) + }) + } + pub fn border_brush(self, value: impl crate::view::IntoProp, M> + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_border_brush(v)) + }) + } + pub fn border_thickness(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_border_thickness(v)) + }) + } + pub fn corner_radius(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_corner_radius(v)) + }) + } + pub fn box_shadow(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_box_shadow(v)) + }) + } + pub fn canvas_left(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_canvas_left(v)) + }) + } + pub fn canvas_top(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_canvas_top(v)) + }) + } + pub fn canvas_right(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_canvas_right(v)) + }) + } + pub fn canvas_bottom(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_canvas_bottom(v)) + }) + } + pub fn dock_panel_dock(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_dock_panel_dock(v)) + }) + } + pub fn grid_column(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_grid_column(v)) + }) + } + pub fn grid_row(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_grid_row(v)) + }) + } + pub fn grid_column_span(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_grid_column_span(v)) + }) + } + pub fn grid_row_span(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_grid_row_span(v)) + }) + } + pub fn grid_is_shared_size_scope(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_grid_is_shared_size_scope(v)) + }) + } + pub fn relative_panel_align_left_with_panel(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_relative_panel_align_left_with_panel(v)) + }) + } + pub fn relative_panel_align_right_with_panel(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_relative_panel_align_right_with_panel(v)) + }) + } + pub fn relative_panel_align_top_with_panel(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_relative_panel_align_top_with_panel(v)) + }) + } + pub fn relative_panel_align_bottom_with_panel(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_relative_panel_align_bottom_with_panel(v)) + }) + } + pub fn relative_panel_align_horizontal_center_with_panel(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_relative_panel_align_horizontal_center_with_panel(v)) + }) + } + pub fn relative_panel_align_vertical_center_with_panel(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_relative_panel_align_vertical_center_with_panel(v)) + }) + } + pub fn tool_tip_tip(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_tool_tip_tip(v)) + }) + } + pub fn tool_tip_is_open(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_tool_tip_is_open(v)) + }) + } + pub fn tool_tip_placement(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_tool_tip_placement(v)) + }) + } + pub fn tool_tip_horizontal_offset(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_tool_tip_horizontal_offset(v)) + }) + } + pub fn tool_tip_vertical_offset(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_tool_tip_vertical_offset(v)) + }) + } + pub fn tool_tip_show_delay(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_tool_tip_show_delay(v)) + }) + } + pub fn tool_tip_between_show_delay(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_tool_tip_between_show_delay(v)) + }) + } + pub fn tool_tip_show_on_disabled(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_tool_tip_show_on_disabled(v)) + }) + } + pub fn tool_tip_service_enabled(self, value: impl crate::view::IntoProp + 'static) -> Self { + let binding = value.into_prop(); + self.with_op(move |_, control| { + crate::view::apply_prop(control, binding, |c, v| c.set_tool_tip_service_enabled(v)) + }) + } + pub fn rsx_child(self, value: impl crate::view::IntoContentEl + 'static) -> Self { + self.child(value) + } +} + +#[repr(transparent)] #[derive(Clone, Debug)] pub struct Button { pub(crate) raw: sys::ComPtr, @@ -4368,6 +6253,9 @@ impl Button { with_factory(|factory| factory.create_button()) .map(|raw| Self { raw }) } + pub fn el() -> crate::view::El { + crate::view::El::new(Self::new) + } pub fn get_name(&self) -> Result> { unsafe { Ok(sys::take_utf16(self.raw.get_name()?)) } } @@ -4580,10 +6468,10 @@ impl Button { pub fn get_margin(&self) -> Result { Ok(self.raw.get_margin()?.into()) } - pub fn set_margin(&self, value: Thickness) -> Result<()> { - Ok(self.raw.set_margin(value.into())?) + pub fn set_margin(&self, value: impl Into) -> Result<()> { + Ok(self.raw.set_margin(value.into().into())?) } - pub fn margin(self, value: Thickness) -> Result { + pub fn margin(self, value: impl Into) -> Result { self.set_margin(value)?; Ok(self) } @@ -4802,20 +6690,20 @@ impl Button { pub fn get_border_thickness(&self) -> Result { Ok(self.raw.get_border_thickness()?.into()) } - pub fn set_border_thickness(&self, value: Thickness) -> Result<()> { - Ok(self.raw.set_border_thickness(value.into())?) + pub fn set_border_thickness(&self, value: impl Into) -> Result<()> { + Ok(self.raw.set_border_thickness(value.into().into())?) } - pub fn border_thickness(self, value: Thickness) -> Result { + pub fn border_thickness(self, value: impl Into) -> Result { self.set_border_thickness(value)?; Ok(self) } pub fn get_corner_radius(&self) -> Result { Ok(self.raw.get_corner_radius()?.into()) } - pub fn set_corner_radius(&self, value: CornerRadius) -> Result<()> { - Ok(self.raw.set_corner_radius(value.into())?) + pub fn set_corner_radius(&self, value: impl Into) -> Result<()> { + Ok(self.raw.set_corner_radius(value.into().into())?) } - pub fn corner_radius(self, value: CornerRadius) -> Result { + pub fn corner_radius(self, value: impl Into) -> Result { self.set_corner_radius(value)?; Ok(self) } @@ -4904,10 +6792,10 @@ impl Button { pub fn get_padding(&self) -> Result { Ok(self.raw.get_padding()?.into()) } - pub fn set_padding(&self, value: Thickness) -> Result<()> { - Ok(self.raw.set_padding(value.into())?) + pub fn set_padding(&self, value: impl Into) -> Result<()> { + Ok(self.raw.set_padding(value.into().into())?) } - pub fn padding(self, value: Thickness) -> Result { + pub fn padding(self, value: impl Into) -> Result { self.set_padding(value)?; Ok(self) } @@ -4922,6 +6810,14 @@ impl Button { self.set_content(value)?; Ok(self) } + pub fn set_content_text(&self, value: impl AsRef) -> Result<()> { + let text_block = TextBlock::new()?.text(value)?; + self.set_content(Some(&text_block)) + } + pub fn content_text(self, value: impl AsRef) -> Result { + self.set_content_text(value)?; + Ok(self) + } pub fn get_content_template(&self) -> Result> { Ok(self.raw.get_content_template()?.map(|raw| DataTemplate { raw })) } @@ -5037,6 +6933,348 @@ impl Button { scope.retain_subscription(self.subscribe_click(callback)?); Ok(self) } + pub fn get_canvas_left(&self) -> Result { + Canvas::get_left(self) + } + pub fn set_canvas_left(&self, value: f64) -> Result<()> { + Canvas::set_left(self, value) + } + pub fn canvas_left(self, value: f64) -> Result { + Canvas::set_left(&self, value)?; + Ok(self) + } + pub fn get_canvas_top(&self) -> Result { + Canvas::get_top(self) + } + pub fn set_canvas_top(&self, value: f64) -> Result<()> { + Canvas::set_top(self, value) + } + pub fn canvas_top(self, value: f64) -> Result { + Canvas::set_top(&self, value)?; + Ok(self) + } + pub fn get_canvas_right(&self) -> Result { + Canvas::get_right(self) + } + pub fn set_canvas_right(&self, value: f64) -> Result<()> { + Canvas::set_right(self, value) + } + pub fn canvas_right(self, value: f64) -> Result { + Canvas::set_right(&self, value)?; + Ok(self) + } + pub fn get_canvas_bottom(&self) -> Result { + Canvas::get_bottom(self) + } + pub fn set_canvas_bottom(&self, value: f64) -> Result<()> { + Canvas::set_bottom(self, value) + } + pub fn canvas_bottom(self, value: f64) -> Result { + Canvas::set_bottom(&self, value)?; + Ok(self) + } + pub fn get_dock_panel_dock(&self) -> Result { + DockPanel::get_dock(self) + } + pub fn set_dock_panel_dock(&self, value: Dock) -> Result<()> { + DockPanel::set_dock(self, value) + } + pub fn dock_panel_dock(self, value: Dock) -> Result { + DockPanel::set_dock(&self, value)?; + Ok(self) + } + pub fn get_grid_column(&self) -> Result { + Grid::get_column(self) + } + pub fn set_grid_column(&self, value: i32) -> Result<()> { + Grid::set_column(self, value) + } + pub fn grid_column(self, value: i32) -> Result { + Grid::set_column(&self, value)?; + Ok(self) + } + pub fn get_grid_row(&self) -> Result { + Grid::get_row(self) + } + pub fn set_grid_row(&self, value: i32) -> Result<()> { + Grid::set_row(self, value) + } + pub fn grid_row(self, value: i32) -> Result { + Grid::set_row(&self, value)?; + Ok(self) + } + pub fn get_grid_column_span(&self) -> Result { + Grid::get_column_span(self) + } + pub fn set_grid_column_span(&self, value: i32) -> Result<()> { + Grid::set_column_span(self, value) + } + pub fn grid_column_span(self, value: i32) -> Result { + Grid::set_column_span(&self, value)?; + Ok(self) + } + pub fn get_grid_row_span(&self) -> Result { + Grid::get_row_span(self) + } + pub fn set_grid_row_span(&self, value: i32) -> Result<()> { + Grid::set_row_span(self, value) + } + pub fn grid_row_span(self, value: i32) -> Result { + Grid::set_row_span(&self, value)?; + Ok(self) + } + pub fn get_grid_is_shared_size_scope(&self) -> Result { + Grid::get_is_shared_size_scope(self) + } + pub fn set_grid_is_shared_size_scope(&self, value: bool) -> Result<()> { + Grid::set_is_shared_size_scope(self, value) + } + pub fn grid_is_shared_size_scope(self, value: bool) -> Result { + Grid::set_is_shared_size_scope(&self, value)?; + Ok(self) + } + pub fn get_relative_panel_align_left_with_panel(&self) -> Result { + RelativePanel::get_align_left_with_panel(self) + } + pub fn set_relative_panel_align_left_with_panel(&self, value: bool) -> Result<()> { + RelativePanel::set_align_left_with_panel(self, value) + } + pub fn relative_panel_align_left_with_panel(self, value: bool) -> Result { + RelativePanel::set_align_left_with_panel(&self, value)?; + Ok(self) + } + pub fn get_relative_panel_align_right_with_panel(&self) -> Result { + RelativePanel::get_align_right_with_panel(self) + } + pub fn set_relative_panel_align_right_with_panel(&self, value: bool) -> Result<()> { + RelativePanel::set_align_right_with_panel(self, value) + } + pub fn relative_panel_align_right_with_panel(self, value: bool) -> Result { + RelativePanel::set_align_right_with_panel(&self, value)?; + Ok(self) + } + pub fn get_relative_panel_align_top_with_panel(&self) -> Result { + RelativePanel::get_align_top_with_panel(self) + } + pub fn set_relative_panel_align_top_with_panel(&self, value: bool) -> Result<()> { + RelativePanel::set_align_top_with_panel(self, value) + } + pub fn relative_panel_align_top_with_panel(self, value: bool) -> Result { + RelativePanel::set_align_top_with_panel(&self, value)?; + Ok(self) + } + pub fn get_relative_panel_align_bottom_with_panel(&self) -> Result { + RelativePanel::get_align_bottom_with_panel(self) + } + pub fn set_relative_panel_align_bottom_with_panel(&self, value: bool) -> Result<()> { + RelativePanel::set_align_bottom_with_panel(self, value) + } + pub fn relative_panel_align_bottom_with_panel(self, value: bool) -> Result { + RelativePanel::set_align_bottom_with_panel(&self, value)?; + Ok(self) + } + pub fn get_relative_panel_align_horizontal_center_with_panel(&self) -> Result { + RelativePanel::get_align_horizontal_center_with_panel(self) + } + pub fn set_relative_panel_align_horizontal_center_with_panel(&self, value: bool) -> Result<()> { + RelativePanel::set_align_horizontal_center_with_panel(self, value) + } + pub fn relative_panel_align_horizontal_center_with_panel(self, value: bool) -> Result { + RelativePanel::set_align_horizontal_center_with_panel(&self, value)?; + Ok(self) + } + pub fn get_relative_panel_align_vertical_center_with_panel(&self) -> Result { + RelativePanel::get_align_vertical_center_with_panel(self) + } + pub fn set_relative_panel_align_vertical_center_with_panel(&self, value: bool) -> Result<()> { + RelativePanel::set_align_vertical_center_with_panel(self, value) + } + pub fn relative_panel_align_vertical_center_with_panel(self, value: bool) -> Result { + RelativePanel::set_align_vertical_center_with_panel(&self, value)?; + Ok(self) + } + pub fn get_tool_tip_tip(&self) -> Result> { + ToolTip::get_tip(self) + } + pub fn set_tool_tip_tip(&self, value: impl AsRef) -> Result<()> { + ToolTip::set_tip(self, value) + } + pub fn tool_tip_tip(self, value: impl AsRef) -> Result { + ToolTip::set_tip(&self, value)?; + Ok(self) + } + pub fn get_tool_tip_is_open(&self) -> Result { + ToolTip::get_is_open(self) + } + pub fn set_tool_tip_is_open(&self, value: bool) -> Result<()> { + ToolTip::set_is_open(self, value) + } + pub fn tool_tip_is_open(self, value: bool) -> Result { + ToolTip::set_is_open(&self, value)?; + Ok(self) + } + pub fn get_tool_tip_placement(&self) -> Result { + ToolTip::get_placement(self) + } + pub fn set_tool_tip_placement(&self, value: PlacementMode) -> Result<()> { + ToolTip::set_placement(self, value) + } + pub fn tool_tip_placement(self, value: PlacementMode) -> Result { + ToolTip::set_placement(&self, value)?; + Ok(self) + } + pub fn get_tool_tip_horizontal_offset(&self) -> Result { + ToolTip::get_horizontal_offset(self) + } + pub fn set_tool_tip_horizontal_offset(&self, value: f64) -> Result<()> { + ToolTip::set_horizontal_offset(self, value) + } + pub fn tool_tip_horizontal_offset(self, value: f64) -> Result { + ToolTip::set_horizontal_offset(&self, value)?; + Ok(self) + } + pub fn get_tool_tip_vertical_offset(&self) -> Result { + ToolTip::get_vertical_offset(self) + } + pub fn set_tool_tip_vertical_offset(&self, value: f64) -> Result<()> { + ToolTip::set_vertical_offset(self, value) + } + pub fn tool_tip_vertical_offset(self, value: f64) -> Result { + ToolTip::set_vertical_offset(&self, value)?; + Ok(self) + } + pub fn get_tool_tip_show_delay(&self) -> Result { + ToolTip::get_show_delay(self) + } + pub fn set_tool_tip_show_delay(&self, value: i32) -> Result<()> { + ToolTip::set_show_delay(self, value) + } + pub fn tool_tip_show_delay(self, value: i32) -> Result { + ToolTip::set_show_delay(&self, value)?; + Ok(self) + } + pub fn get_tool_tip_between_show_delay(&self) -> Result { + ToolTip::get_between_show_delay(self) + } + pub fn set_tool_tip_between_show_delay(&self, value: i32) -> Result<()> { + ToolTip::set_between_show_delay(self, value) + } + pub fn tool_tip_between_show_delay(self, value: i32) -> Result { + ToolTip::set_between_show_delay(&self, value)?; + Ok(self) + } + pub fn get_tool_tip_show_on_disabled(&self) -> Result { + ToolTip::get_show_on_disabled(self) + } + pub fn set_tool_tip_show_on_disabled(&self, value: bool) -> Result<()> { + ToolTip::set_show_on_disabled(self, value) + } + pub fn tool_tip_show_on_disabled(self, value: bool) -> Result { + ToolTip::set_show_on_disabled(&self, value)?; + Ok(self) + } + pub fn get_tool_tip_service_enabled(&self) -> Result { + ToolTip::get_service_enabled(self) + } + pub fn set_tool_tip_service_enabled(&self, value: bool) -> Result<()> { + ToolTip::set_service_enabled(self, value) + } + pub fn tool_tip_service_enabled(self, value: bool) -> Result { + ToolTip::set_service_enabled(&self, value)?; + Ok(self) + } +} + +impl std::ops::Deref for Button { + type Target = ContentControl; + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Self as *const Self::Target) } + } +} + +unsafe impl crate::Upcast for Button { + fn upcast(&self) -> AvaloniaObject { + AvaloniaObject { + raw: unsafe { self.raw.cast_clone() }, + } + } + fn upcast_ref(&self) -> &AvaloniaObject { + unsafe { &*(self as *const Self as *const AvaloniaObject) } + } +} + +impl AsRef for Button { + fn as_ref(&self) -> &AvaloniaObject { + >::upcast_ref(self) + } +} + +unsafe impl crate::Upcast for Button { + fn upcast(&self) -> StyledElement { + StyledElement { + raw: unsafe { self.raw.cast_clone() }, + } + } + fn upcast_ref(&self) -> &StyledElement { + unsafe { &*(self as *const Self as *const StyledElement) } + } +} + +impl AsRef for Button { + fn as_ref(&self) -> &StyledElement { + >::upcast_ref(self) + } +} + +unsafe impl crate::Upcast for Button { + fn upcast(&self) -> Control { + Control { + raw: unsafe { self.raw.cast_clone() }, + } + } + fn upcast_ref(&self) -> &Control { + unsafe { &*(self as *const Self as *const Control) } + } +} + +impl AsRef for Button { + fn as_ref(&self) -> &Control { + >::upcast_ref(self) + } +} + +unsafe impl crate::Upcast for Button { + fn upcast(&self) -> TemplatedControl { + TemplatedControl { + raw: unsafe { self.raw.cast_clone() }, + } + } + fn upcast_ref(&self) -> &TemplatedControl { + unsafe { &*(self as *const Self as *const TemplatedControl) } + } +} + +impl AsRef for Button { + fn as_ref(&self) -> &TemplatedControl { + >::upcast_ref(self) + } +} + +unsafe impl crate::Upcast for Button { + fn upcast(&self) -> ContentControl { + ContentControl { + raw: unsafe { self.raw.cast_clone() }, + } + } + fn upcast_ref(&self) -> &ContentControl { + unsafe { &*(self as *const Self as *const ContentControl) } + } +} + +impl AsRef for Button { + fn as_ref(&self) -> &ContentControl { + >::upcast_ref(self) + } } impl AsControl for Button { @@ -5045,6 +7283,520 @@ impl AsControl for Button { } } +impl crate::view::El + + + + +"##; + + let rust_code = compile_axaml(axaml).expect("AXAML should compile to Rust"); + assert!(rust_code.contains("pub struct LoginWindowRefs")); + assert!(rust_code.contains("pub header_text: rustolonia::NodeRef")); + assert!(rust_code.contains("pub username_input: rustolonia::NodeRef")); + assert!(rust_code.contains("pub submit_button: rustolonia::NodeRef")); + assert!(rust_code.contains("pub struct LoginWindowBindings")); + assert!(rust_code.contains("pub username: rustolonia::Signal")); + assert!(rust_code.contains("pub remember_me: rustolonia::Signal")); + assert!(rust_code.contains("pub status_message: rustolonia::Signal")); + assert!(rust_code.contains("pub fn build_login_window(bindings: &LoginWindowBindings)")); + assert!( + rust_code.contains(".padding(rustolonia::Thickness::symmetric(24.0_f64, 16.0_f64))") + ); + assert!(rust_code.contains(".corner_radius(rustolonia::CornerRadius::uniform(8.0_f64))")); + assert!(rust_code.contains(".orientation(rustolonia::Orientation::Vertical)")); + assert!(rust_code.contains(".grid_row(0_i32)")); + assert!(rust_code.contains(".grid_column(1_i32)")); + assert!(rust_code.contains(".dock_panel_dock(rustolonia::Dock::Top)")); + assert!(rust_code.contains(".tool_tip_tip(\"Enter your username\")")); + assert!(rust_code.contains(".text(bindings.username.two_way())")); + assert!(rust_code.contains(".checked(bindings.remember_me.two_way())")); + assert!(rust_code.contains(".text(bindings.status_message)")); + } + + #[test] + fn compiles_axaml_events_string_format_and_data_template() { + let axaml = r##" + + + + + + + + Row item + + + + + +"##; + + let rust_code = + compile_axaml(axaml).expect("AXAML with events and DataTemplate should compile"); + assert!(rust_code.contains("pub struct TaskWindowHandlers")); + assert!(rust_code.contains("pub on_add_task: Box")); + assert!(rust_code.contains(".on_click(handlers.on_add_task)")); + assert!(rust_code.contains("format!(\"{} items\", __sig.get())")); + assert!(rust_code.contains("rustolonia::data_template_reactive")); + assert!(rust_code.contains("control.set_item_template(Some(&tpl))")); + } + + #[test] + fn rejects_unknown_control_or_property_in_axaml() { + assert!(compile_axaml("").is_err()); + assert!(compile_axaml("