diff --git a/src/Fabulous.MauiControls/AppHostBuilderExtensions.fs b/src/Fabulous.MauiControls/AppHostBuilderExtensions.fs index c629b01..458ff81 100644 --- a/src/Fabulous.MauiControls/AppHostBuilderExtensions.fs +++ b/src/Fabulous.MauiControls/AppHostBuilderExtensions.fs @@ -53,6 +53,24 @@ type AppHostBuilderExtensions = static member UseFabulousApp(this: MauiAppBuilder, program: Program) : MauiAppBuilder = this.UseFabulousApp(program, ()) + [] + static member UseFabulousApp(this: MauiAppBuilder, program: Program<'arg, 'model, 'msg, Memo.Memoized<#IFabApplication>>, arg: 'arg) : MauiAppBuilder = + this.UseFabulousApp( + program.CanReuseView, + program.State.Logger, + program.SyncAction, + fun () -> + (View.Component(program.State, arg) { + let! model = Mvu.State + program.View model + }) + .Compile() + ) + + [] + static member UseFabulousApp(this: MauiAppBuilder, program: Program>) : MauiAppBuilder = + this.UseFabulousApp(program, ()) + [] static member UseFabulousApp ( diff --git a/src/Fabulous.MauiControls/Attributes.fs b/src/Fabulous.MauiControls/Attributes.fs index 45726fa..0cc6460 100644 --- a/src/Fabulous.MauiControls/Attributes.fs +++ b/src/Fabulous.MauiControls/Attributes.fs @@ -16,14 +16,24 @@ type ImageSourceValue = | Stream of stream: Stream [] -type ValueEventData<'data, 'eventArgs> = +type MsgValueEventData<'data, 'eventArgs> = { Value: 'data Event: 'eventArgs -> MsgValue } -module ValueEventData = +module MsgValueEventData = let create (value: 'data) (event: 'eventArgs -> 'msg) = { Value = value Event = event >> box >> MsgValue } + +[] +type ValueEventData<'data, 'eventArgs> = + { Value: 'data + Event: 'eventArgs -> unit } + +module ValueEventData = + let create (value: 'data) (event: 'eventArgs -> unit) = + { Value = value + Event = event } /// Maui.Controls specific attributes that can be encoded as 8 bytes module SmallScalars = @@ -157,12 +167,12 @@ module Attributes = name (bindableProperty: BindableProperty) (getEvent: obj -> IEvent, 'args>) - : SimpleScalarAttributeDefinition> = + : SimpleScalarAttributeDefinition> = let key = SimpleScalarAttributeDefinition.CreateAttributeData( ScalarAttributeComparers.noCompare, - (fun oldValueOpt (newValueOpt: ValueEventData<'data, 'args> voption) node -> + (fun oldValueOpt (newValueOpt: MsgValueEventData<'data, 'args> voption) node -> let target = node.Target :?> BindableObject match newValueOpt with @@ -199,3 +209,51 @@ module Attributes = |> AttributeDefinitionStore.registerScalar { Key = key; Name = name } + + /// Update both a property and its related event. + /// This definition makes sure that the event is only raised when the property is changed by the user, + /// and not when the property is set by the code + let defineBindableWithEventNoDispatch<'data, 'args> + name + (bindableProperty: BindableProperty) + (getEvent: obj -> IEvent, 'args>) + : SimpleScalarAttributeDefinition> = + + let key = + SimpleScalarAttributeDefinition.CreateAttributeData( + ScalarAttributeComparers.noCompare, + (fun oldValueOpt (newValueOpt: ValueEventData<'data, 'args> voption) node -> + let target = node.Target :?> BindableObject + + match newValueOpt with + | ValueNone -> + // The attribute is no longer applied, so we clean up the event + match node.TryGetHandler(name) with + | ValueNone -> () + | ValueSome handler -> handler.Dispose() + + // Only clear the property if a value was set before + match oldValueOpt with + | ValueNone -> () + | ValueSome _ -> target.ClearValue(bindableProperty) + + | ValueSome curr -> + // Clean up the old event handler if any + match node.TryGetHandler(name) with + | ValueNone -> () + | ValueSome handler -> handler.Dispose() + + // Set the new value + target.SetValue(bindableProperty, curr.Value) + + // Set the new event handler + let event = getEvent target + + let handler = + event.Subscribe(curr.Event) + + node.SetHandler(name, handler)) + ) + |> AttributeDefinitionStore.registerScalar + + { Key = key; Name = name } diff --git a/src/Fabulous.MauiControls/Component.fs b/src/Fabulous.MauiControls/Component.fs index 1dc69ad..3e907a5 100644 --- a/src/Fabulous.MauiControls/Component.fs +++ b/src/Fabulous.MauiControls/Component.fs @@ -17,10 +17,10 @@ module Component = module ComponentBuilders = type Fabulous.Maui.View with - static member inline Component<'msg, 'marker>() = ComponentBuilder<'msg>() + static member inline Component<'msg, 'marker when 'msg : equality>() = ComponentBuilder<'msg>() - static member inline Component<'msg, 'model, 'marker, 'parentMsg>(program: Program) = + static member inline Component<'msg, 'model, 'marker, 'parentMsg when 'msg : equality and 'parentMsg : equality>(program: Program) = MvuComponentBuilder(program, ()) - static member inline Component<'arg, 'msg, 'model, 'marker, 'parentMsg>(program: Program<'arg, 'model, 'msg>, arg: 'arg) = + static member inline Component<'arg, 'msg, 'model, 'marker, 'parentMsg when 'msg : equality and 'parentMsg : equality>(program: Program<'arg, 'model, 'msg>, arg: 'arg) = MvuComponentBuilder<'arg, 'msg, 'model, 'marker, 'parentMsg>(program, arg) diff --git a/src/Fabulous.MauiControls/Fabulous.MauiControls.fsproj b/src/Fabulous.MauiControls/Fabulous.MauiControls.fsproj index 27294cf..9bc4e01 100644 --- a/src/Fabulous.MauiControls/Fabulous.MauiControls.fsproj +++ b/src/Fabulous.MauiControls/Fabulous.MauiControls.fsproj @@ -1,6 +1,6 @@ - false + true net8.0 true @@ -102,6 +102,7 @@ + diff --git a/src/Fabulous.MauiControls/Style.fs b/src/Fabulous.MauiControls/Style.fs index 616f494..a56811d 100644 --- a/src/Fabulous.MauiControls/Style.fs +++ b/src/Fabulous.MauiControls/Style.fs @@ -9,7 +9,7 @@ type FabElementExtensions = /// Current widget /// The style modifier function [] - static member inline style<'msg, 'marker when 'marker :> IFabElement> + static member inline style<'msg, 'marker when 'msg : equality and 'marker :> IFabElement> ( this: WidgetBuilder<'msg, 'marker>, fn: WidgetBuilder<'msg, 'marker> -> WidgetBuilder<'msg, 'marker> diff --git a/src/Fabulous.MauiControls/Views/Application.fs b/src/Fabulous.MauiControls/Views/Application.fs index a5551b3..e8df396 100644 --- a/src/Fabulous.MauiControls/Views/Application.fs +++ b/src/Fabulous.MauiControls/Views/Application.fs @@ -67,32 +67,59 @@ module Application = Attributes.definePropertyWidget "Application_MainPage" (fun target -> (target :?> Application).MainPage :> obj) (fun target value -> (target :?> Application).MainPage <- value) - let ModalPopped = - Attributes.defineEvent "Application_ModalPopped" (fun target -> (target :?> Application).ModalPopped) + let ModalPoppedMsg = + Attributes.defineEvent "Application_ModalPoppedMsg" (fun target -> (target :?> Application).ModalPopped) - let ModalPopping = - Attributes.defineEvent "Application_ModalPopping" (fun target -> (target :?> Application).ModalPopping) + let ModalPoppedFn = + Attributes.defineEventNoDispatch "Application_ModalPoppedFn" (fun target -> (target :?> Application).ModalPopped) - let ModalPushed = - Attributes.defineEvent "Application_ModalPushed" (fun target -> (target :?> Application).ModalPushed) + let ModalPoppingMsg = + Attributes.defineEvent "Application_ModalPoppingMsg" (fun target -> (target :?> Application).ModalPopping) - let ModalPushing = - Attributes.defineEvent "Application_ModalPushing" (fun target -> (target :?> Application).ModalPushing) + let ModalPoppingFn = + Attributes.defineEventNoDispatch "Application_ModalPoppingFn" (fun target -> (target :?> Application).ModalPopping) - let RequestedThemeChanged = - Attributes.defineEvent "Application_RequestedThemeChanged" (fun target -> (target :?> Application).RequestedThemeChanged) + let ModalPushedMsg = + Attributes.defineEvent "Application_ModalPushedMsg" (fun target -> (target :?> Application).ModalPushed) - let Resume = - Attributes.defineEventNoArg "Application_Resume" (fun target -> (target :?> FabApplication).Resume) + let ModalPushedFn = + Attributes.defineEventNoDispatch "Application_ModalPushedFn" (fun target -> (target :?> Application).ModalPushed) - let Sleep = - Attributes.defineEventNoArg "Application_Sleep" (fun target -> (target :?> FabApplication).Sleep) + let ModalPushingMsg = + Attributes.defineEvent "Application_ModalPushingMsg" (fun target -> (target :?> Application).ModalPushing) - let Start = - Attributes.defineEventNoArg "Application_Start" (fun target -> (target :?> FabApplication).Start) + let ModalPushingFn = + Attributes.defineEventNoDispatch "Application_ModalPushingFn" (fun target -> (target :?> Application).ModalPushing) - let AppLinkRequestReceived = - Attributes.defineEvent "Application_AppLinkRequestReceived" (fun target -> (target :?> FabApplication).AppLinkRequestReceived) + let RequestedThemeChangedMsg = + Attributes.defineEvent "Application_RequestedThemeChangedMsg" (fun target -> (target :?> Application).RequestedThemeChanged) + + let RequestedThemeChangedFn = + Attributes.defineEventNoDispatch "Application_RequestedThemeChangedFn" (fun target -> (target :?> Application).RequestedThemeChanged) + + let ResumeMsg = + Attributes.defineEventNoArg "Application_ResumeMsg" (fun target -> (target :?> FabApplication).Resume) + + let ResumeFn = + Attributes.defineEventNoArgNoDispatch "Application_ResumeFn" (fun target -> (target :?> FabApplication).Resume) + + let SleepMsg = + Attributes.defineEventNoArg "Application_SleepMsg" (fun target -> (target :?> FabApplication).Sleep) + + let SleepFn = + Attributes.defineEventNoArgNoDispatch "Application_SleepFn" (fun target -> (target :?> FabApplication).Sleep) + + let StartMsg = + Attributes.defineEventNoArg "Application_StartMsg" (fun target -> (target :?> FabApplication).Start) + + let StartFn = + Attributes.defineEventNoArgNoDispatch "Application_StartFn" (fun target -> (target :?> FabApplication).Start) + + let AppLinkRequestReceivedMsg = + Attributes.defineEvent "Application_AppLinkRequestReceivedMsg" (fun target -> (target :?> FabApplication).AppLinkRequestReceived) + + let AppLinkRequestReceivedFn = + Attributes.defineEventNoDispatch "Application_AppLinkRequestReceivedFn" (fun target -> (target :?> FabApplication).AppLinkRequestReceived) let UserAppTheme = Attributes.defineEnum "Application_UserAppTheme" (fun _ newValueOpt node -> @@ -118,7 +145,7 @@ module ApplicationBuilders = WidgetHelpers.buildWidgets<'msg, IFabApplication> Application.WidgetKey [| Application.MainPage.WithValue(mainPage.Compile()) |] /// Create an Application widget with a list of windows - static member inline Application<'msg, 'itemMarker when 'itemMarker :> IFabWindow>() = + static member inline Application<'msg, 'itemMarker when 'msg : equality and 'itemMarker :> IFabWindow>() = CollectionBuilder<'msg, IFabApplication, 'itemMarker>(Application.WidgetKey, Application.Windows) [] @@ -128,63 +155,126 @@ type ApplicationModifiers = /// Message to dispatch [] static member inline onModalPopped(this: WidgetBuilder<'msg, #IFabApplication>, fn: ModalPoppedEventArgs -> 'msg) = - this.AddScalar(Application.ModalPopped.WithValue(fn)) + this.AddScalar(Application.ModalPoppedMsg.WithValue(fn)) + + /// Listen for the ModalPopped event + /// Current widget + /// Message to dispatch + [] + static member inline onModalPopped(this: WidgetBuilder<'msg, #IFabApplication>, fn: ModalPoppedEventArgs -> unit) = + this.AddScalar(Application.ModalPoppedFn.WithValue(fn)) /// Listen for the ModalPopping event /// Current widget /// Message to dispatch [] static member inline onModalPopping(this: WidgetBuilder<'msg, #IFabApplication>, fn: ModalPoppingEventArgs -> 'msg) = - this.AddScalar(Application.ModalPopping.WithValue(fn)) + this.AddScalar(Application.ModalPoppingMsg.WithValue(fn)) + + /// Listen for the ModalPopping event + /// Current widget + /// Message to dispatch + [] + static member inline onModalPopping(this: WidgetBuilder<'msg, #IFabApplication>, fn: ModalPoppingEventArgs -> unit) = + this.AddScalar(Application.ModalPoppingFn.WithValue(fn)) /// Listen for the ModalPushed event /// Current widget /// Message to dispatch [] static member inline onModalPushed(this: WidgetBuilder<'msg, #IFabApplication>, fn: ModalPushedEventArgs -> 'msg) = - this.AddScalar(Application.ModalPushed.WithValue(fn)) + this.AddScalar(Application.ModalPushedMsg.WithValue(fn)) + + /// Listen for the ModalPushed event + /// Current widget + /// Message to dispatch + [] + static member inline onModalPushed(this: WidgetBuilder<'msg, #IFabApplication>, fn: ModalPushedEventArgs -> unit) = + this.AddScalar(Application.ModalPushedFn.WithValue(fn)) /// Listen for the ModalPushing event /// Current widget /// Message to dispatch [] static member inline onModalPushing(this: WidgetBuilder<'msg, #IFabApplication>, fn: ModalPushingEventArgs -> 'msg) = - this.AddScalar(Application.ModalPushing.WithValue(fn)) + this.AddScalar(Application.ModalPushingMsg.WithValue(fn)) + + /// Listen for the ModalPushing event + /// Current widget + /// Message to dispatch + [] + static member inline onModalPushing(this: WidgetBuilder<'msg, #IFabApplication>, fn: ModalPushingEventArgs -> unit) = + this.AddScalar(Application.ModalPushingFn.WithValue(fn)) /// Listen for the Resume event /// Current widget /// Message to dispatch [] static member inline onResume(this: WidgetBuilder<'msg, #IFabApplication>, msg: 'msg) = - this.AddScalar(Application.Resume.WithValue(MsgValue(msg))) + this.AddScalar(Application.ResumeMsg.WithValue(MsgValue(msg))) + + /// Listen for the Resume event + /// Current widget + /// Function to execute + [] + static member inline onResume(this: WidgetBuilder<'msg, #IFabApplication>, fn: unit -> unit) = + this.AddScalar(Application.ResumeFn.WithValue(fn)) /// Listen for the Start event /// Current widget /// Message to dispatch [] static member inline onStart(this: WidgetBuilder<'msg, #IFabApplication>, msg: 'msg) = - this.AddScalar(Application.Start.WithValue(MsgValue(msg))) + this.AddScalar(Application.StartMsg.WithValue(MsgValue(msg))) + + /// Listen for the Start event + /// Current widget + /// Function to execute + [] + static member inline onStart(this: WidgetBuilder<'msg, #IFabApplication>, fn: unit -> unit) = + this.AddScalar(Application.StartFn.WithValue(fn)) /// Listen for the Sleep event /// Current widget /// Message to dispatch [] static member inline onSleep(this: WidgetBuilder<'msg, #IFabApplication>, msg: 'msg) = - this.AddScalar(Application.Sleep.WithValue(MsgValue(msg))) + this.AddScalar(Application.SleepMsg.WithValue(MsgValue(msg))) + + /// Listen for the Sleep event + /// Current widget + /// Function to execute + [] + static member inline onSleep(this: WidgetBuilder<'msg, #IFabApplication>, fn: unit -> unit) = + this.AddScalar(Application.SleepFn.WithValue(fn)) /// Listen for the RequestedThemeChanged event /// Current widget /// Message to dispatch [] static member inline onRequestedThemeChanged(this: WidgetBuilder<'msg, #IFabApplication>, fn: AppTheme -> 'msg) = - this.AddScalar(Application.RequestedThemeChanged.WithValue(fun args -> fn args.RequestedTheme |> box)) + this.AddScalar(Application.RequestedThemeChangedMsg.WithValue(fun args -> fn args.RequestedTheme |> box)) + + /// Listen for the RequestedThemeChanged event + /// Current widget + /// Message to dispatch + [] + static member inline onRequestedThemeChanged(this: WidgetBuilder<'msg, #IFabApplication>, fn: AppTheme -> unit) = + this.AddScalar(Application.RequestedThemeChangedFn.WithValue(fun args -> fn args.RequestedTheme)) /// Listen for the AppLinkRequestReceived event /// Current widget /// Message to dispatch [] static member inline onAppLinkRequestReceived(this: WidgetBuilder<'msg, #IFabApplication>, fn: Uri -> 'msg) = - this.AddScalar(Application.AppLinkRequestReceived.WithValue(fun args -> fn args |> box)) + this.AddScalar(Application.AppLinkRequestReceivedMsg.WithValue(fun args -> fn args |> box)) + + /// Listen for the AppLinkRequestReceived event + /// Current widget + /// Message to dispatch + [] + static member inline onAppLinkRequestReceived(this: WidgetBuilder<'msg, #IFabApplication>, fn: Uri -> unit) = + this.AddScalar(Application.AppLinkRequestReceivedFn.WithValue(fun args -> fn args)) /// Set the user app theme /// Current widget @@ -203,7 +293,7 @@ type ApplicationModifiers = [] type ApplicationYieldExtensions = [] - static member inline Yield<'msg, 'marker, 'itemType when 'marker :> IFabApplication and 'itemType :> IFabWindow> + static member inline Yield<'msg, 'marker, 'itemType when 'msg : equality and 'marker :> IFabApplication and 'itemType :> IFabWindow> ( _: CollectionBuilder<'msg, 'marker, IFabWindow>, x: WidgetBuilder<'msg, 'itemType> diff --git a/src/Fabulous.MauiControls/Views/Brushes/LinearGradientBrush.fs b/src/Fabulous.MauiControls/Views/Brushes/LinearGradientBrush.fs index 5c961fa..fabc9fd 100644 --- a/src/Fabulous.MauiControls/Views/Brushes/LinearGradientBrush.fs +++ b/src/Fabulous.MauiControls/Views/Brushes/LinearGradientBrush.fs @@ -21,13 +21,13 @@ module LinearGradientBrushBuilders = type Fabulous.Maui.View with /// Create a LinearGradientBrush widgets that paints an area with a linear gradient, which blends two or more colors along a line known as the gradient axis - static member inline LinearGradientBrush<'msg>() = + static member inline LinearGradientBrush() = CollectionBuilder<'msg, IFabLinearGradientBrush, IFabGradientStop>(LinearGradientBrush.WidgetKey, GradientBrush.Children) /// Create a LinearGradientBrush widgets that paints an area with a linear gradient, which blends two or more colors along a line known as the gradient axis /// EndPoint, of type Point, which represents the ending two-dimensional coordinates of the linear gradient /// StartPoint, of type Point, which represents the starting two-dimensional coordinates of the linear gradient - static member inline LinearGradientBrush<'msg>(startPoint: Point, endPoint: Point) = + static member inline LinearGradientBrush(startPoint: Point, endPoint: Point) = CollectionBuilder<'msg, IFabLinearGradientBrush, IFabGradientStop>( LinearGradientBrush.WidgetKey, GradientBrush.Children, diff --git a/src/Fabulous.MauiControls/Views/Brushes/RadialGradientBrush.fs b/src/Fabulous.MauiControls/Views/Brushes/RadialGradientBrush.fs index a446c40..37dc1dd 100644 --- a/src/Fabulous.MauiControls/Views/Brushes/RadialGradientBrush.fs +++ b/src/Fabulous.MauiControls/Views/Brushes/RadialGradientBrush.fs @@ -22,7 +22,7 @@ module RadialGradientBrushBuilders = /// Create a RadialGradientBrush widget that paints an area with a radial gradient, which blends two or more colors across a circle /// Center, of type Point, which represents the center point of the circle for the radial gradient /// Radius, of type float, which represents the radius of the circle for the radial gradient - static member inline RadialGradientBrush<'msg>(center: Point, radius: float) = + static member inline RadialGradientBrush(center: Point, radius: float) = CollectionBuilder<'msg, IFabRadialGradientBrush, IFabGradientStop>( RadialGradientBrush.WidgetKey, GradientBrush.Children, @@ -31,5 +31,5 @@ module RadialGradientBrushBuilders = ) /// Create a RadialGradientBrush widget that paints an area with a radial gradient, which blends two or more colors across a circle - static member inline RadialGradientBrush<'msg>() = + static member inline RadialGradientBrush() = CollectionBuilder<'msg, IFabRadialGradientBrush, IFabGradientStop>(RadialGradientBrush.WidgetKey, GradientBrush.Children) diff --git a/src/Fabulous.MauiControls/Views/Cells/EntryCell.fs b/src/Fabulous.MauiControls/Views/Cells/EntryCell.fs index 00d229e..7dac65d 100644 --- a/src/Fabulous.MauiControls/Views/Cells/EntryCell.fs +++ b/src/Fabulous.MauiControls/Views/Cells/EntryCell.fs @@ -46,14 +46,20 @@ module EntryCell = let LabelColor = Attributes.defineBindableColor EntryCell.LabelColorProperty - let OnCompleted = - Attributes.defineEventNoArg "EntryCell_Completed" (fun target -> (target :?> EntryCell).Completed) + let OnCompletedMsg = + Attributes.defineEventNoArg "EntryCell_CompletedMsg" (fun target -> (target :?> EntryCell).Completed) + + let OnCompletedFn = + Attributes.defineEventNoArgNoDispatch "EntryCell_CompletedFn" (fun target -> (target :?> EntryCell).Completed) let Placeholder = Attributes.defineBindableWithEquality EntryCell.PlaceholderProperty - let TextWithEvent = - Attributes.defineBindableWithEvent "EntryCell_TextChanged" EntryCell.TextProperty (fun target -> (target :?> FabEntryCell).TextChanged) + let TextWithEventMsg = + Attributes.defineBindableWithEvent "EntryCell_TextChangedMsg" EntryCell.TextProperty (fun target -> (target :?> FabEntryCell).TextChanged) + + let TextWithEventFn = + Attributes.defineBindableWithEventNoDispatch "EntryCell_TextChangedFn" EntryCell.TextProperty (fun target -> (target :?> FabEntryCell).TextChanged) let VerticalTextAlignment = Attributes.defineBindableEnum EntryCell.VerticalTextAlignmentProperty @@ -66,11 +72,22 @@ module EntryCellBuilders = /// The label value /// The text value /// Message to dispatch - static member inline EntryCell<'msg>(label: string, text: string, onTextChanged: string -> 'msg) = + static member inline EntryCell(label: string, text: string, onTextChanged: string -> 'msg) = WidgetBuilder<'msg, IFabEntryCell>( EntryCell.WidgetKey, EntryCell.Label.WithValue(label), - EntryCell.TextWithEvent.WithValue(ValueEventData.create text (fun (args: TextChangedEventArgs) -> onTextChanged args.NewTextValue)) + EntryCell.TextWithEventMsg.WithValue(MsgValueEventData.create text (fun (args: TextChangedEventArgs) -> onTextChanged args.NewTextValue)) + ) + + /// Create an EntryCell with a label, a text, and listen to text changes + /// The label value + /// The text value + /// Message to dispatch + static member inline EntryCell(label: string, text: string, onTextChanged: string -> unit) = + WidgetBuilder<'msg, IFabEntryCell>( + EntryCell.WidgetKey, + EntryCell.Label.WithValue(label), + EntryCell.TextWithEventFn.WithValue(ValueEventData.create text (fun (args: TextChangedEventArgs) -> onTextChanged args.NewTextValue)) ) [] @@ -101,7 +118,14 @@ type EntryCellModifiers = /// Message to dispatch [] static member inline onCompleted(this: WidgetBuilder<'msg, #IFabEntryCell>, msg: 'msg) = - this.AddScalar(EntryCell.OnCompleted.WithValue(MsgValue(msg))) + this.AddScalar(EntryCell.OnCompletedMsg.WithValue(MsgValue(msg))) + + /// Listen to the Completed event + /// Current widget + /// Function to execute + [] + static member inline onCompleted(this: WidgetBuilder<'msg, #IFabEntryCell>, fn: unit -> unit) = + this.AddScalar(EntryCell.OnCompletedFn.WithValue(fn)) /// Set the placeholder text /// Current widget diff --git a/src/Fabulous.MauiControls/Views/Cells/ImageCell.fs b/src/Fabulous.MauiControls/Views/Cells/ImageCell.fs index ee4c0c0..1784c47 100644 --- a/src/Fabulous.MauiControls/Views/Cells/ImageCell.fs +++ b/src/Fabulous.MauiControls/Views/Cells/ImageCell.fs @@ -21,7 +21,7 @@ module ImageCellBuilders = /// Create an ImageCell widget with a text and an image source /// The text of the cell /// The image source - static member inline ImageCell<'msg>(text: string, source: ImageSource) = + static member inline ImageCell(text: string, source: ImageSource) = WidgetBuilder<'msg, IFabImageCell>( ImageCell.WidgetKey, TextCell.Text.WithValue(text), @@ -31,7 +31,7 @@ module ImageCellBuilders = /// Create an ImageCell widget with a text and an image source /// The text of the cell /// The image source - static member inline ImageCell<'msg>(text: string, source: string) = + static member inline ImageCell(text: string, source: string) = WidgetBuilder<'msg, IFabImageCell>( ImageCell.WidgetKey, TextCell.Text.WithValue(text), @@ -41,13 +41,13 @@ module ImageCellBuilders = /// Create an ImageCell widget with a text and an image source /// The text of the cell /// The image source - static member inline ImageCell<'msg>(text: string, source: Uri) = + static member inline ImageCell(text: string, source: Uri) = WidgetBuilder<'msg, IFabImageCell>(ImageCell.WidgetKey, TextCell.Text.WithValue(text), ImageCell.ImageSource.WithValue(ImageSourceValue.Uri source)) /// Create an ImageCell widget with a text and an image source /// The text of the cell /// The image source - static member inline ImageCell<'msg>(text: string, source: Stream) = + static member inline ImageCell(text: string, source: Stream) = WidgetBuilder<'msg, IFabImageCell>( ImageCell.WidgetKey, TextCell.Text.WithValue(text), diff --git a/src/Fabulous.MauiControls/Views/Cells/SwitchCell.fs b/src/Fabulous.MauiControls/Views/Cells/SwitchCell.fs index e7ef8cd..7e52c69 100644 --- a/src/Fabulous.MauiControls/Views/Cells/SwitchCell.fs +++ b/src/Fabulous.MauiControls/Views/Cells/SwitchCell.fs @@ -13,8 +13,11 @@ module SwitchCell = let OnColor = Attributes.defineBindableColor SwitchCell.OnColorProperty - let OnWithEvent = - Attributes.defineBindableWithEvent "SwitchCell_OnChanged" SwitchCell.OnProperty (fun target -> (target :?> SwitchCell).OnChanged) + let OnWithEventMsg = + Attributes.defineBindableWithEvent "SwitchCell_OnChangedMsg" SwitchCell.OnProperty (fun target -> (target :?> SwitchCell).OnChanged) + + let OnWithEventFn = + Attributes.defineBindableWithEventNoDispatch "SwitchCell_OnChangedFn" SwitchCell.OnProperty (fun target -> (target :?> SwitchCell).OnChanged) let Text = Attributes.defineBindableWithEquality SwitchCell.TextProperty @@ -26,10 +29,21 @@ module SwitchCellBuilders = /// The text value /// The toggle state value /// Change callback - static member inline SwitchCell<'msg>(text: string, value: bool, onChanged: bool -> 'msg) = + static member inline SwitchCell(text: string, value: bool, onChanged: bool -> 'msg) = + WidgetBuilder<'msg, IFabSwitchCell>( + SwitchCell.WidgetKey, + SwitchCell.OnWithEventMsg.WithValue(MsgValueEventData.create value (fun (args: ToggledEventArgs) -> onChanged args.Value)), + SwitchCell.Text.WithValue(text) + ) + + /// Create a SwitchCell with a text, a toggle state, and listen to toggle state changes + /// The text value + /// The toggle state value + /// Change callback + static member inline SwitchCell(text: string, value: bool, onChanged: bool -> unit) = WidgetBuilder<'msg, IFabSwitchCell>( SwitchCell.WidgetKey, - SwitchCell.OnWithEvent.WithValue(ValueEventData.create value (fun (args: ToggledEventArgs) -> onChanged args.Value)), + SwitchCell.OnWithEventFn.WithValue(ValueEventData.create value (fun (args: ToggledEventArgs) -> onChanged args.Value)), SwitchCell.Text.WithValue(text) ) diff --git a/src/Fabulous.MauiControls/Views/Cells/TextCell.fs b/src/Fabulous.MauiControls/Views/Cells/TextCell.fs index 05e9239..9706b2d 100644 --- a/src/Fabulous.MauiControls/Views/Cells/TextCell.fs +++ b/src/Fabulous.MauiControls/Views/Cells/TextCell.fs @@ -25,7 +25,7 @@ module TextCellBuilders = /// Create a TextCell widget with a text /// The text value - static member inline TextCell<'msg>(text: string) = + static member inline TextCell(text: string) = WidgetBuilder<'msg, IFabTextCell>(TextCell.WidgetKey, TextCell.Text.WithValue(text)) [] diff --git a/src/Fabulous.MauiControls/Views/Cells/ViewCell.fs b/src/Fabulous.MauiControls/Views/Cells/ViewCell.fs index 4141670..a7bdb67 100644 --- a/src/Fabulous.MauiControls/Views/Cells/ViewCell.fs +++ b/src/Fabulous.MauiControls/Views/Cells/ViewCell.fs @@ -20,7 +20,7 @@ module ViewCellBuilders = /// Create a ViewCell with a content widget /// The content widget - static member inline ViewCell<'msg, 'marker when 'marker :> IFabView>(view: WidgetBuilder<'msg, 'marker>) = + static member inline ViewCell(view: WidgetBuilder<'msg, #IFabView>) = WidgetHelpers.buildWidgets<'msg, IFabViewCell> ViewCell.WidgetKey [| ViewCell.View.WithValue(view.Compile()) |] [] diff --git a/src/Fabulous.MauiControls/Views/Cells/_Cell.fs b/src/Fabulous.MauiControls/Views/Cells/_Cell.fs index f7ebfdf..f01cd38 100644 --- a/src/Fabulous.MauiControls/Views/Cells/_Cell.fs +++ b/src/Fabulous.MauiControls/Views/Cells/_Cell.fs @@ -9,11 +9,17 @@ type IFabCell = inherit IFabElement module Cell = - let Appearing = - Attributes.defineEventNoArg "Cell_Appearing" (fun target -> (target :?> Cell).Appearing) + let AppearingMsg = + Attributes.defineEventNoArg "Cell_AppearingMsg" (fun target -> (target :?> Cell).Appearing) + + let AppearingFn = + Attributes.defineEventNoArgNoDispatch "Cell_AppearingFn" (fun target -> (target :?> Cell).Appearing) - let Disappearing = - Attributes.defineEventNoArg "Cell_Disappearing" (fun target -> (target :?> Cell).Disappearing) + let DisappearingMsg = + Attributes.defineEventNoArg "Cell_DisappearingMsg" (fun target -> (target :?> Cell).Disappearing) + + let DisappearingFn = + Attributes.defineEventNoArgNoDispatch "Cell_DisappearingFn" (fun target -> (target :?> Cell).Disappearing) let Height = Attributes.defineFloat "Cell_Height" (fun _ newValueOpt node -> @@ -28,8 +34,11 @@ module Cell = let IsEnabled = Attributes.defineBindableBool Cell.IsEnabledProperty - let Tapped = - Attributes.defineEventNoArg "Cell_Tapped" (fun target -> (target :?> Cell).Tapped) + let TappedMsg = + Attributes.defineEventNoArg "Cell_TappedMsg" (fun target -> (target :?> Cell).Tapped) + + let TappedFn = + Attributes.defineEventNoArgNoDispatch "Cell_TappedFn" (fun target -> (target :?> Cell).Tapped) let ContextActions = Attributes.defineListWidgetCollection "Cell_ContextActions" (fun target -> (target :?> Cell).ContextActions) @@ -55,32 +64,53 @@ type CellModifiers = /// Message to dispatch [] static member inline onAppearing(this: WidgetBuilder<'msg, #IFabCell>, msg: 'msg) = - this.AddScalar(Cell.Appearing.WithValue(MsgValue(msg))) + this.AddScalar(Cell.AppearingMsg.WithValue(MsgValue(msg))) + + /// Listen to the Appearing event + /// Current widget + /// Function to execute + [] + static member inline onAppearing(this: WidgetBuilder<'msg, #IFabCell>, fn: unit -> unit) = + this.AddScalar(Cell.AppearingFn.WithValue(fn)) /// Listen to the Disappearing event /// Current widget /// Message to dispatch [] static member inline onDisappearing(this: WidgetBuilder<'msg, #IFabCell>, msg: 'msg) = - this.AddScalar(Cell.Disappearing.WithValue(MsgValue(msg))) + this.AddScalar(Cell.DisappearingMsg.WithValue(MsgValue(msg))) + + /// Listen to the Disappearing event + /// Current widget + /// Function to execute + [] + static member inline onDisappearing(this: WidgetBuilder<'msg, #IFabCell>, fn: unit -> unit) = + this.AddScalar(Cell.DisappearingFn.WithValue(fn)) /// Listen to the Tapped event /// Current widget /// Message to dispatch [] static member inline onTapped(this: WidgetBuilder<'msg, #IFabCell>, msg: 'msg) = - this.AddScalar(Cell.Tapped.WithValue(MsgValue(msg))) + this.AddScalar(Cell.TappedMsg.WithValue(MsgValue(msg))) + + /// Listen to the Tapped event + /// Current widget + /// Function to execute + [] + static member inline onTapped(this: WidgetBuilder<'msg, #IFabCell>, fn: unit -> unit) = + this.AddScalar(Cell.TappedFn.WithValue(fn)) /// Set the context actions of the cell /// Current widget [] - static member inline contextActions<'msg, 'marker when 'marker :> IFabCell>(this: WidgetBuilder<'msg, 'marker>) = + static member inline contextActions<'msg, 'marker when 'msg : equality and 'marker :> IFabCell>(this: WidgetBuilder<'msg, 'marker>) = WidgetHelpers.buildAttributeCollection<'msg, 'marker, IFabMenuItem> Cell.ContextActions this [] type CellYieldExtensions = [] - static member inline Yield<'msg, 'marker, 'itemType when 'marker :> IFabCell and 'itemType :> IFabMenuItem> + static member inline Yield<'msg, 'marker, 'itemType when 'msg : equality and 'marker :> IFabCell and 'itemType :> IFabMenuItem> ( _: AttributeCollectionBuilder<'msg, 'marker, IFabMenuItem>, x: WidgetBuilder<'msg, 'itemType> diff --git a/src/Fabulous.MauiControls/Views/Collections/CarouselView.fs b/src/Fabulous.MauiControls/Views/Collections/CarouselView.fs index 6bf433d..e2f1f2b 100644 --- a/src/Fabulous.MauiControls/Views/Collections/CarouselView.fs +++ b/src/Fabulous.MauiControls/Views/Collections/CarouselView.fs @@ -1,6 +1,5 @@ namespace Fabulous.Maui -open System open System.Runtime.CompilerServices open Fabulous open Microsoft.Maui @@ -62,7 +61,7 @@ module CarouselViewBuilders = /// Create a CarouselView widget with a list of items /// The items list - static member inline CarouselView<'msg, 'itemData, 'itemMarker when 'itemMarker :> IFabView>(items: seq<'itemData>) = + static member inline CarouselView<'msg, 'itemData, 'itemMarker when 'msg : equality and 'itemMarker :> IFabView>(items: seq<'itemData>) = WidgetHelpers.buildItems<'msg, IFabCarouselView, 'itemData, 'itemMarker> CarouselView.WidgetKey ItemsView.ItemsSource items [] diff --git a/src/Fabulous.MauiControls/Views/Collections/CollectionView.fs b/src/Fabulous.MauiControls/Views/Collections/CollectionView.fs index 73e8c07..232368b 100644 --- a/src/Fabulous.MauiControls/Views/Collections/CollectionView.fs +++ b/src/Fabulous.MauiControls/Views/Collections/CollectionView.fs @@ -48,8 +48,11 @@ module CollectionView = let ItemSizingStrategy = Attributes.defineBindableEnum CollectionView.ItemSizingStrategyProperty - let SelectionChanged = - Attributes.defineEvent "CollectionView_SelectionChanged" (fun target -> (target :?> CollectionView).SelectionChanged) + let SelectionChangedMsg = + Attributes.defineEvent "CollectionView_SelectionChangedMsg" (fun target -> (target :?> CollectionView).SelectionChanged) + + let SelectionChangedFn = + Attributes.defineEventNoDispatch "CollectionView_SelectionChangedFn" (fun target -> (target :?> CollectionView).SelectionChanged) let SelectionMode = Attributes.defineBindableEnum CollectionView.SelectionModeProperty @@ -60,13 +63,13 @@ module CollectionViewBuilders = /// Create a CollectionView widget with a list of items /// The items list - static member inline CollectionView<'msg, 'itemData, 'itemMarker when 'itemMarker :> IFabView>(items: seq<'itemData>) = + static member inline CollectionView<'msg, 'itemData, 'itemMarker when 'msg : equality and 'itemMarker :> IFabView>(items: seq<'itemData>) = WidgetHelpers.buildItems<'msg, IFabCollectionView, 'itemData, 'itemMarker> CollectionView.WidgetKey ItemsView.ItemsSource items /// Create a CollectionView widget with a list of grouped items /// The grouped items list static member inline GroupedCollectionView<'msg, 'groupData, 'groupMarker, 'itemData, 'itemMarker - when 'itemMarker :> IFabView and 'groupMarker :> IFabView and 'groupData :> System.Collections.Generic.IEnumerable<'itemData>> + when 'msg : equality and 'itemMarker :> IFabView and 'groupMarker :> IFabView and 'groupData :> System.Collections.Generic.IEnumerable<'itemData>> (items: seq<'groupData>) = WidgetHelpers.buildGroupItems<'msg, IFabCollectionView, 'groupData, 'itemData, 'groupMarker, 'itemMarker> @@ -102,7 +105,14 @@ type CollectionViewModifiers = /// Message to dispatch [] static member inline onSelectionChanged(this: WidgetBuilder<'msg, #IFabCollectionView>, fn: SelectionChangedEventArgs -> 'msg) = - this.AddScalar(CollectionView.SelectionChanged.WithValue(fun args -> fn args |> box)) + this.AddScalar(CollectionView.SelectionChangedMsg.WithValue(fun args -> fn args |> box)) + + /// Listen for the SelectionChanged event + /// Current widget + /// Message to dispatch + [] + static member inline onSelectionChanged(this: WidgetBuilder<'msg, #IFabCollectionView>, fn: SelectionChangedEventArgs -> unit) = + this.AddScalar(CollectionView.SelectionChangedFn.WithValue(fn)) /// Set the selection mode /// Current widget diff --git a/src/Fabulous.MauiControls/Views/Collections/ListView.fs b/src/Fabulous.MauiControls/Views/Collections/ListView.fs index 3cacb16..5ce6c3f 100644 --- a/src/Fabulous.MauiControls/Views/Collections/ListView.fs +++ b/src/Fabulous.MauiControls/Views/Collections/ListView.fs @@ -1,6 +1,5 @@ namespace Fabulous.Maui -open System open System.Runtime.CompilerServices open Fabulous open Microsoft.Maui @@ -54,23 +53,38 @@ module ListView = let IsRefreshing = Attributes.defineBindableBool ListView.IsRefreshingProperty - let ItemAppearing = - Attributes.defineEvent "ListView_ItemAppearing" (fun target -> (target :?> ListView).ItemAppearing) + let ItemAppearingMsg = + Attributes.defineEvent "ListView_ItemAppearingMsg" (fun target -> (target :?> ListView).ItemAppearing) - let ItemDisappearing = - Attributes.defineEvent "ListView_ItemDisappearing" (fun target -> (target :?> ListView).ItemDisappearing) + let ItemAppearingFn = + Attributes.defineEventNoDispatch "ListView_ItemAppearingFn" (fun target -> (target :?> ListView).ItemAppearing) - let ItemSelected = - Attributes.defineEvent "ListView_ItemSelected" (fun target -> (target :?> ListView).ItemSelected) + let ItemDisappearingMsg = + Attributes.defineEvent "ListView_ItemDisappearingMsg" (fun target -> (target :?> ListView).ItemDisappearing) - let ItemTapped = - Attributes.defineEvent "ListView_ItemTapped" (fun target -> (target :?> ListView).ItemTapped) + let ItemDisappearingFn = + Attributes.defineEventNoDispatch "ListView_ItemDisappearingFn" (fun target -> (target :?> ListView).ItemDisappearing) + + let ItemSelectedMsg = + Attributes.defineEvent "ListView_ItemSelectedMsg" (fun target -> (target :?> ListView).ItemSelected) + + let ItemSelectedFn = + Attributes.defineEventNoDispatch "ListView_ItemSelectedFn" (fun target -> (target :?> ListView).ItemSelected) + + let ItemTappedMsg = + Attributes.defineEvent "ListView_ItemTappedMsg" (fun target -> (target :?> ListView).ItemTapped) + + let ItemTappedFn = + Attributes.defineEvent "ListView_ItemTappedFn" (fun target -> (target :?> ListView).ItemTapped) let RefreshControlColor = Attributes.defineBindableColor ListView.RefreshControlColorProperty - let Refreshing = - Attributes.defineEventNoArg "ListView_Refreshing" (fun target -> (target :?> ListView).Refreshing) + let RefreshingMsg = + Attributes.defineEventNoArg "ListView_RefreshingMsg" (fun target -> (target :?> ListView).Refreshing) + + let RefreshingFn = + Attributes.defineEventNoArgNoDispatch "ListView_RefreshingFn" (fun target -> (target :?> ListView).Refreshing) let RowHeight = Attributes.defineBindableInt ListView.RowHeightProperty @@ -82,11 +96,17 @@ module ListView = let SeparatorVisibility = Attributes.defineBindableEnum ListView.SeparatorVisibilityProperty - let Scrolled = - Attributes.defineEvent "ListView_Scrolled" (fun target -> (target :?> ListView).Scrolled) + let ScrolledMsg = + Attributes.defineEvent "ListView_ScrolledMsg" (fun target -> (target :?> ListView).Scrolled) + + let ScrolledFn = + Attributes.defineEventNoDispatch "ListView_ScrolledFn" (fun target -> (target :?> ListView).Scrolled) - let ScrollToRequested = - Attributes.defineEvent "ListView_ScrollToRequested" (fun target -> (target :?> ListView).ScrollToRequested) + let ScrollToRequestedMsg = + Attributes.defineEvent "ListView_ScrollToRequestedMsg" (fun target -> (target :?> ListView).ScrollToRequested) + + let ScrollToRequestedFn = + Attributes.defineEventNoDispatch "ListView_ScrollToRequestedFn" (fun target -> (target :?> ListView).ScrollToRequested) let VerticalScrollBarVisibility = Attributes.defineBindableEnum ListView.VerticalScrollBarVisibilityProperty @@ -97,13 +117,13 @@ module ListViewBuilders = /// Create a ListView with a list of items /// The items list - static member inline ListView<'msg, 'itemData, 'itemMarker when 'itemMarker :> IFabCell>(items: seq<'itemData>) = + static member inline ListView<'msg, 'itemData, 'itemMarker when 'msg : equality and 'itemMarker :> IFabCell>(items: seq<'itemData>) = WidgetHelpers.buildItems<'msg, IFabListView, 'itemData, 'itemMarker> ListView.WidgetKey ItemsViewOfCell.ItemsSource items /// Create a ListView with a list of grouped items /// The grouped items list static member inline GroupedListView<'msg, 'groupData, 'groupMarker, 'itemData, 'itemMarker - when 'itemMarker :> IFabCell and 'groupMarker :> IFabCell and 'groupData :> System.Collections.Generic.IEnumerable<'itemData>> + when 'msg : equality and 'itemMarker :> IFabCell and 'groupMarker :> IFabCell and 'groupData :> System.Collections.Generic.IEnumerable<'itemData>> (items: seq<'groupData>) = WidgetHelpers.buildGroupItemsNoFooter<'msg, IFabListView, 'groupData, 'itemData, 'groupMarker, 'itemMarker> @@ -160,49 +180,98 @@ type ListViewModifiers = /// Message to dispatch [] static member inline onItemAppearing(this: WidgetBuilder<'msg, #IFabListView>, fn: ItemVisibilityEventArgs -> 'msg) = - this.AddScalar(ListView.ItemAppearing.WithValue(fun args -> fn args |> box)) + this.AddScalar(ListView.ItemAppearingMsg.WithValue(fun args -> fn args |> box)) + + /// Listen for the ItemAppearing event + /// Current widget + /// Message to dispatch + [] + static member inline onItemAppearing(this: WidgetBuilder<'msg, #IFabListView>, fn: ItemVisibilityEventArgs -> unit) = + this.AddScalar(ListView.ItemAppearingFn.WithValue(fn)) /// Listen for the ItemDisappearing event /// Current widget /// Message to dispatch [] static member inline onItemDisappearing(this: WidgetBuilder<'msg, #IFabListView>, fn: ItemVisibilityEventArgs -> 'msg) = - this.AddScalar(ListView.ItemDisappearing.WithValue(fun args -> fn args |> box)) + this.AddScalar(ListView.ItemDisappearingMsg.WithValue(fun args -> fn args |> box)) + + /// Listen for the ItemDisappearing event + /// Current widget + /// Message to dispatch + [] + static member inline onItemDisappearing(this: WidgetBuilder<'msg, #IFabListView>, fn: ItemVisibilityEventArgs -> unit) = + this.AddScalar(ListView.ItemDisappearingFn.WithValue(fn)) /// Listen for the ItemTapped event /// Current widget /// Message to dispatch [] static member inline onItemTapped(this: WidgetBuilder<'msg, #IFabListView>, fn: int -> 'msg) = - this.AddScalar(ListView.ItemTapped.WithValue(fun args -> fn args.ItemIndex |> box)) + this.AddScalar(ListView.ItemTappedMsg.WithValue(fun args -> fn args.ItemIndex |> box)) + + /// Listen for the ItemTapped event + /// Current widget + /// Message to dispatch + [] + static member inline onItemTapped(this: WidgetBuilder<'msg, #IFabListView>, fn: int -> unit) = + this.AddScalar(ListView.ItemTappedFn.WithValue(fun args -> fn args.ItemIndex)) /// Listen for the ItemSelected event /// Current widget /// Message to dispatch [] static member inline onItemSelected(this: WidgetBuilder<'msg, #IFabListView>, fn: int -> 'msg) = - this.AddScalar(ListView.ItemSelected.WithValue(fun args -> fn args.SelectedItemIndex |> box)) + this.AddScalar(ListView.ItemSelectedMsg.WithValue(fun args -> fn args.SelectedItemIndex |> box)) + + /// Listen for the ItemSelected event + /// Current widget + /// Message to dispatch + [] + static member inline onItemSelected(this: WidgetBuilder<'msg, #IFabListView>, fn: int -> unit) = + this.AddScalar(ListView.ItemSelectedFn.WithValue(fun args -> fn args.SelectedItemIndex)) /// Listen for the Refreshing event /// Current widget /// Message to dispatch [] static member inline onRefreshing(this: WidgetBuilder<'msg, #IFabListView>, msg: 'msg) = - this.AddScalar(ListView.Refreshing.WithValue(MsgValue(msg))) + this.AddScalar(ListView.RefreshingMsg.WithValue(MsgValue(msg))) + + /// Listen for the Refreshing event + /// Current widget + /// Function to execute + [] + static member inline onRefreshing(this: WidgetBuilder<'msg, #IFabListView>, fn: unit -> unit) = + this.AddScalar(ListView.RefreshingFn.WithValue(fn)) /// Listen for the Scrolled event /// Current widget /// Message to dispatch [] static member inline onScrolled(this: WidgetBuilder<'msg, #IFabListView>, fn: ScrolledEventArgs -> 'msg) = - this.AddScalar(ListView.Scrolled.WithValue(fun args -> fn args |> box)) + this.AddScalar(ListView.ScrolledMsg.WithValue(fun args -> fn args |> box)) + + /// Listen for the Scrolled event + /// Current widget + /// Message to dispatch + [] + static member inline onScrolled(this: WidgetBuilder<'msg, #IFabListView>, fn: ScrolledEventArgs -> unit) = + this.AddScalar(ListView.ScrolledFn.WithValue(fn)) /// Listen for the ScrollToRequested event /// Current widget /// Message to dispatch [] static member inline onScrollToRequested(this: WidgetBuilder<'msg, #IFabListView>, fn: ScrollToRequestedEventArgs -> 'msg) = - this.AddScalar(ListView.ScrollToRequested.WithValue(fun args -> fn args |> box)) + this.AddScalar(ListView.ScrollToRequestedMsg.WithValue(fun args -> fn args |> box)) + + /// Listen for the ScrollToRequested event + /// Current widget + /// Message to dispatch + [] + static member inline onScrollToRequested(this: WidgetBuilder<'msg, #IFabListView>, fn: ScrollToRequestedEventArgs -> unit) = + this.AddScalar(ListView.ScrollToRequestedFn.WithValue(fn)) /// Set the refresh control color /// Current widget diff --git a/src/Fabulous.MauiControls/Views/Collections/_ItemsView.fs b/src/Fabulous.MauiControls/Views/Collections/_ItemsView.fs index 14d67e2..2d8da54 100644 --- a/src/Fabulous.MauiControls/Views/Collections/_ItemsView.fs +++ b/src/Fabulous.MauiControls/Views/Collections/_ItemsView.fs @@ -36,14 +36,23 @@ module ItemsView = let RemainingItemsThreshold = Attributes.defineBindableInt ItemsView.RemainingItemsThresholdProperty - let RemainingItemsThresholdReached = - Attributes.defineEventNoArg "ItemsView_RemainingItemsThresholdReached" (fun target -> (target :?> ItemsView).RemainingItemsThresholdReached) + let RemainingItemsThresholdReachedMsg = + Attributes.defineEventNoArg "ItemsView_RemainingItemsThresholdReachedMsg" (fun target -> (target :?> ItemsView).RemainingItemsThresholdReached) - let Scrolled = - Attributes.defineEvent "ItemsView_Scrolled" (fun target -> (target :?> ItemsView).Scrolled) + let RemainingItemsThresholdReachedFn = + Attributes.defineEventNoArgNoDispatch "ItemsView_RemainingItemsThresholdReachedFn" (fun target -> (target :?> ItemsView).RemainingItemsThresholdReached) - let ScrollToRequested = - Attributes.defineEvent "ItemsView_ScrolledRequested" (fun target -> (target :?> ItemsView).ScrollToRequested) + let ScrolledMsg = + Attributes.defineEvent "ItemsView_ScrolledMsg" (fun target -> (target :?> ItemsView).Scrolled) + + let ScrolledFn = + Attributes.defineEventNoDispatch "ItemsView_ScrolledFn" (fun target -> (target :?> ItemsView).Scrolled) + + let ScrollToRequestedMsg = + Attributes.defineEvent "ItemsView_ScrolledRequestedMsg" (fun target -> (target :?> ItemsView).ScrollToRequested) + + let ScrollToRequestedFn = + Attributes.defineEventNoDispatch "ItemsView_ScrolledRequestedFn" (fun target -> (target :?> ItemsView).ScrollToRequested) let VerticalScrollBarVisibility = Attributes.defineBindableEnum ItemsView.VerticalScrollBarVisibilityProperty @@ -76,14 +85,28 @@ type ItemsViewModifiers = /// Message to dispatch [] static member inline onScrolled(this: WidgetBuilder<'msg, #IFabItemsView>, fn: ItemsViewScrolledEventArgs -> 'msg) = - this.AddScalar(ItemsView.Scrolled.WithValue(fun args -> fn args |> box)) + this.AddScalar(ItemsView.ScrolledMsg.WithValue(fun args -> fn args |> box)) + + /// Listen for the Scrolled event + /// Current widget + /// Message to dispatch + [] + static member inline onScrolled(this: WidgetBuilder<'msg, #IFabItemsView>, fn: ItemsViewScrolledEventArgs -> unit) = + this.AddScalar(ItemsView.ScrolledFn.WithValue(fn)) /// Listen for the ScrollToRequested event /// Current widget /// Message to dispatch [] static member inline onScrollToRequested(this: WidgetBuilder<'msg, #IFabItemsView>, fn: ScrollToRequestEventArgs -> 'msg) = - this.AddScalar(ItemsView.ScrollToRequested.WithValue(fun args -> fn args |> box)) + this.AddScalar(ItemsView.ScrollToRequestedMsg.WithValue(fun args -> fn args |> box)) + + /// Listen for the ScrollToRequested event + /// Current widget + /// Message to dispatch + [] + static member inline onScrollToRequested(this: WidgetBuilder<'msg, #IFabItemsView>, fn: ScrollToRequestEventArgs -> unit) = + this.AddScalar(ItemsView.ScrollToRequestedFn.WithValue(fn)) /// Set the threshold of items not yet visible in the list at which the RemainingItemsThresholdReached event will be fired /// Current widget @@ -93,7 +116,17 @@ type ItemsViewModifiers = static member inline remainingItemsThreshold(this: WidgetBuilder<'msg, #IFabItemsView>, value: int, onThresholdReached: 'msg) = this .AddScalar(ItemsView.RemainingItemsThreshold.WithValue(value)) - .AddScalar(ItemsView.RemainingItemsThresholdReached.WithValue(MsgValue(onThresholdReached))) + .AddScalar(ItemsView.RemainingItemsThresholdReachedMsg.WithValue(MsgValue(onThresholdReached))) + + /// Set the threshold of items not yet visible in the list at which the RemainingItemsThresholdReached event will be fired + /// Current widget + /// The threshold of items not yet visible in the list + /// Message to dispatch + [] + static member inline remainingItemsThreshold(this: WidgetBuilder<'msg, #IFabItemsView>, value: int, onThresholdReached: unit -> unit) = + this + .AddScalar(ItemsView.RemainingItemsThreshold.WithValue(value)) + .AddScalar(ItemsView.RemainingItemsThresholdReachedFn.WithValue(onThresholdReached)) /// Set the visibility of the vertical scroll bar /// Current widget diff --git a/src/Fabulous.MauiControls/Views/Controls/ActivityIndicator.fs b/src/Fabulous.MauiControls/Views/Controls/ActivityIndicator.fs index bcc5fe6..a3eb7c7 100644 --- a/src/Fabulous.MauiControls/Views/Controls/ActivityIndicator.fs +++ b/src/Fabulous.MauiControls/Views/Controls/ActivityIndicator.fs @@ -21,7 +21,7 @@ module ActivityIndicatorBuilders = /// Create an ActivityIndicator widget with a running state /// The running state - static member inline ActivityIndicator<'msg>(isRunning: bool) = + static member inline ActivityIndicator(isRunning: bool) = WidgetBuilder<'msg, IFabActivityIndicator>(ActivityIndicator.WidgetKey, ActivityIndicator.IsRunning.WithValue(isRunning)) [] diff --git a/src/Fabulous.MauiControls/Views/Controls/BoxView.fs b/src/Fabulous.MauiControls/Views/Controls/BoxView.fs index 70656fa..8f6e062 100644 --- a/src/Fabulous.MauiControls/Views/Controls/BoxView.fs +++ b/src/Fabulous.MauiControls/Views/Controls/BoxView.fs @@ -21,7 +21,7 @@ module BoxViewBuilders = /// Create a BoxView widget with a color /// The color value - static member inline BoxView<'msg>(color: Color) = + static member inline BoxView(color: Color) = WidgetBuilder<'msg, IFabBoxView>(BoxView.WidgetKey, BoxView.Color.WithValue(color)) [] diff --git a/src/Fabulous.MauiControls/Views/Controls/Button.fs b/src/Fabulous.MauiControls/Views/Controls/Button.fs index c3fc004..05f4347 100644 --- a/src/Fabulous.MauiControls/Views/Controls/Button.fs +++ b/src/Fabulous.MauiControls/Views/Controls/Button.fs @@ -21,11 +21,11 @@ module Button = let CharacterSpacing = Attributes.defineBindableFloat Button.CharacterSpacingProperty - let Clicked = - Attributes.defineEventNoArg "Button_Clicked" (fun target -> (target :?> Button).Clicked) + let ClickedMsg = + Attributes.defineEventNoArg "Button_ClickedMsg" (fun target -> (target :?> Button).Clicked) - let Clicked' = - Attributes.defineEventNoArgNoDispatch "Button_Clicked" (fun target -> (target :?> Button).Clicked) + let ClickedFn = + Attributes.defineEventNoArgNoDispatch "Button_ClickedFn" (fun target -> (target :?> Button).Clicked) let ContentLayout = Attributes.defineBindableWithEquality Button.ContentLayoutProperty @@ -51,11 +51,17 @@ module Button = let Padding = Attributes.defineBindableWithEquality Button.PaddingProperty - let Pressed = - Attributes.defineEventNoArg "Button_Pressed" (fun target -> (target :?> Button).Pressed) + let PressedMsg = + Attributes.defineEventNoArg "Button_PressedMsg" (fun target -> (target :?> Button).Pressed) - let Released = - Attributes.defineEventNoArg "Button_Released" (fun target -> (target :?> Button).Released) + let PressedFn = + Attributes.defineEventNoArgNoDispatch "Button_PressedFn" (fun target -> (target :?> Button).Pressed) + + let ReleasedMsg = + Attributes.defineEventNoArg "Button_ReleasedMsg" (fun target -> (target :?> Button).Released) + + let ReleasedFn = + Attributes.defineEventNoArgNoDispatch "Button_ReleasedFn" (fun target -> (target :?> Button).Released) let Text = Attributes.defineBindableWithEquality Button.TextProperty @@ -71,14 +77,14 @@ module ButtonBuilders = /// Create a Button widget with a text and listen for the Click event /// The button on the tex /// Message to dispatch - static member inline Button<'msg>(text: string, onClicked: 'msg) = - WidgetBuilder<'msg, IFabButton>(Button.WidgetKey, Button.Text.WithValue(text), Button.Clicked.WithValue(MsgValue(onClicked))) + static member inline Button(text: string, onClicked: 'msg) = + WidgetBuilder<'msg, IFabButton>(Button.WidgetKey, Button.Text.WithValue(text), Button.ClickedMsg.WithValue(MsgValue(onClicked))) /// Create a Button widget with a text and listen for the Click event /// The button on the tex /// Function to execute static member inline Button(text: string, onClicked: unit -> unit) = - WidgetBuilder(Button.WidgetKey, Button.Text.WithValue(text), Button.Clicked'.WithValue(onClicked)) + WidgetBuilder<'msg, IFabButton>(Button.WidgetKey, Button.Text.WithValue(text), Button.ClickedFn.WithValue(onClicked)) [] type ButtonModifiers = @@ -178,14 +184,28 @@ type ButtonModifiers = /// Message to dispatch [] static member inline onPressed(this: WidgetBuilder<'msg, #IFabButton>, msg: 'msg) = - this.AddScalar(Button.Pressed.WithValue(MsgValue(msg))) + this.AddScalar(Button.PressedMsg.WithValue(MsgValue(msg))) + + /// Listen for the Pressed event + /// Current widget + /// Function to execute + [] + static member inline onPressed(this: WidgetBuilder<'msg, #IFabButton>, fn: unit -> unit) = + this.AddScalar(Button.PressedFn.WithValue(fn)) /// Listen for the Released event /// Current widget /// Message to dispatch [] static member inline onReleased(this: WidgetBuilder<'msg, #IFabButton>, msg: 'msg) = - this.AddScalar(Button.Released.WithValue(MsgValue(msg))) + this.AddScalar(Button.ReleasedMsg.WithValue(MsgValue(msg))) + + /// Listen for the Released event + /// Current widget + /// Function to execute + [] + static member inline onReleased(this: WidgetBuilder<'msg, #IFabButton>, fn: unit -> unit) = + this.AddScalar(Button.ReleasedFn.WithValue(fn)) /// Set the padding inside the button /// Current widget diff --git a/src/Fabulous.MauiControls/Views/Controls/CheckBox.fs b/src/Fabulous.MauiControls/Views/Controls/CheckBox.fs index d1514ce..3f62ff2 100644 --- a/src/Fabulous.MauiControls/Views/Controls/CheckBox.fs +++ b/src/Fabulous.MauiControls/Views/Controls/CheckBox.fs @@ -13,8 +13,11 @@ module CheckBox = let Color = Attributes.defineBindableColor CheckBox.ColorProperty - let IsCheckedWithEvent = - Attributes.defineBindableWithEvent "CheckBox_CheckedChanged" CheckBox.IsCheckedProperty (fun target -> (target :?> CheckBox).CheckedChanged) + let IsCheckedWithEventMsg = + Attributes.defineBindableWithEvent "CheckBox_CheckedChangedMsg" CheckBox.IsCheckedProperty (fun target -> (target :?> CheckBox).CheckedChanged) + + let IsCheckedWithEventFn = + Attributes.defineBindableWithEventNoDispatch "CheckBox_CheckedChangedFn" CheckBox.IsCheckedProperty (fun target -> (target :?> CheckBox).CheckedChanged) [] module CheckBoxBuilders = @@ -23,10 +26,19 @@ module CheckBoxBuilders = /// Create a CheckBox widget with a state and listen for state changes /// The state of the checkbox /// Message to dispatch - static member inline CheckBox<'msg>(isChecked: bool, onCheckedChanged: bool -> 'msg) = + static member inline CheckBox(isChecked: bool, onCheckedChanged: bool -> 'msg) = + WidgetBuilder<'msg, IFabCheckBox>( + CheckBox.WidgetKey, + CheckBox.IsCheckedWithEventMsg.WithValue(MsgValueEventData.create isChecked (fun (args: CheckedChangedEventArgs) -> onCheckedChanged args.Value)) + ) + + /// Create a CheckBox widget with a state and listen for state changes + /// The state of the checkbox + /// Message to dispatch + static member inline CheckBox(isChecked: bool, onCheckedChanged: bool -> unit) = WidgetBuilder<'msg, IFabCheckBox>( CheckBox.WidgetKey, - CheckBox.IsCheckedWithEvent.WithValue(ValueEventData.create isChecked (fun (args: CheckedChangedEventArgs) -> onCheckedChanged args.Value)) + CheckBox.IsCheckedWithEventFn.WithValue(ValueEventData.create isChecked (fun (args: CheckedChangedEventArgs) -> onCheckedChanged args.Value)) ) [] diff --git a/src/Fabulous.MauiControls/Views/Controls/DatePicker.fs b/src/Fabulous.MauiControls/Views/Controls/DatePicker.fs index 6c10e8e..76f6274 100644 --- a/src/Fabulous.MauiControls/Views/Controls/DatePicker.fs +++ b/src/Fabulous.MauiControls/Views/Controls/DatePicker.fs @@ -16,8 +16,8 @@ module DatePicker = let CharacterSpacing = Attributes.defineBindableFloat DatePicker.CharacterSpacingProperty - let DateWithEvent = - let name = "DatePicker_DateSelected" + let DateWithEventMsg = + let name = "DatePicker_DateSelectedMsg" let minProperty = DatePicker.MinimumDateProperty let valueProperty = DatePicker.DateProperty let maxProperty = DatePicker.MaximumDateProperty @@ -25,7 +25,7 @@ module DatePicker = let key = ScalarAttributeDefinitions.SimpleScalarAttributeDefinition.CreateAttributeData( ScalarAttributeComparers.noCompare, - (fun oldValueOpt (newValueOpt: ValueEventData voption) node -> + (fun oldValueOpt (newValueOpt: MsgValueEventData voption) node -> let target = node.Target :?> DatePicker match newValueOpt with @@ -65,6 +65,56 @@ module DatePicker = ) |> AttributeDefinitionStore.registerScalar + { Key = key; Name = name } + : ScalarAttributeDefinitions.SimpleScalarAttributeDefinition> + + let DateWithEventFn = + let name = "DatePicker_DateSelectedFn" + let minProperty = DatePicker.MinimumDateProperty + let valueProperty = DatePicker.DateProperty + let maxProperty = DatePicker.MaximumDateProperty + + let key = + ScalarAttributeDefinitions.SimpleScalarAttributeDefinition.CreateAttributeData( + ScalarAttributeComparers.noCompare, + (fun oldValueOpt (newValueOpt: ValueEventData voption) node -> + let target = node.Target :?> DatePicker + + match newValueOpt with + | ValueNone -> + // The attribute is no longer applied, so we clean up the event + match node.TryGetHandler(name) with + | ValueNone -> () + | ValueSome handler -> handler.Dispose() + + // Only clear the property if a value was set before + match oldValueOpt with + | ValueNone -> () + | ValueSome _ -> + target.ClearValue(minProperty) + target.ClearValue(maxProperty) + target.ClearValue(valueProperty) + + | ValueSome curr -> + // Clean up the old event handler if any + match node.TryGetHandler(name) with + | ValueNone -> () + | ValueSome handler -> handler.Dispose() + + // Set the new value + let struct (min, max, value) = curr.Value + target.SetValue(minProperty, min) + target.SetValue(maxProperty, max) + target.SetValue(valueProperty, value) + + // Set the new event handler + let handler = + target.DateSelected.Subscribe(curr.Event) + + node.SetHandler(name, handler)) + ) + |> AttributeDefinitionStore.registerScalar + { Key = key; Name = name } : ScalarAttributeDefinitions.SimpleScalarAttributeDefinition> @@ -104,10 +154,23 @@ module DatePickerBuilders = /// The maximum date allowed /// The selected date /// Message to dispatch - static member inline DatePicker<'msg>(min: DateTime, max: DateTime, date: DateTime, onDateSelected: DateTime -> 'msg) = + static member inline DatePicker(min: DateTime, max: DateTime, date: DateTime, onDateSelected: DateTime -> 'msg) = + WidgetBuilder<'msg, IFabDatePicker>( + DatePicker.WidgetKey, + DatePicker.DateWithEventMsg.WithValue( + MsgValueEventData.create (struct (min, max, date)) (fun (args: DateChangedEventArgs) -> onDateSelected args.NewDate) + ) + ) + + /// Create a DatePicker widget with a date, min-max bounds and listen for the date changes + /// The minimum date allowed + /// The maximum date allowed + /// The selected date + /// Message to dispatch + static member inline DatePicker(min: DateTime, max: DateTime, date: DateTime, onDateSelected: DateTime -> unit) = WidgetBuilder<'msg, IFabDatePicker>( DatePicker.WidgetKey, - DatePicker.DateWithEvent.WithValue( + DatePicker.DateWithEventFn.WithValue( ValueEventData.create (struct (min, max, date)) (fun (args: DateChangedEventArgs) -> onDateSelected args.NewDate) ) ) diff --git a/src/Fabulous.MauiControls/Views/Controls/Editor.fs b/src/Fabulous.MauiControls/Views/Controls/Editor.fs index 3306cab..44c53e5 100644 --- a/src/Fabulous.MauiControls/Views/Controls/Editor.fs +++ b/src/Fabulous.MauiControls/Views/Controls/Editor.fs @@ -14,8 +14,11 @@ module Editor = let AutoSize = Attributes.defineBindableEnum Editor.AutoSizeProperty - let Completed = - Attributes.defineEventNoArg "Editor_Completed" (fun target -> (target :?> Editor).Completed) + let CompletedMsg = + Attributes.defineEventNoArg "Editor_CompletedMsg" (fun target -> (target :?> Editor).Completed) + + let CompletedFn = + Attributes.defineEventNoArgNoDispatch "Editor_CompletedFn" (fun target -> (target :?> Editor).Completed) let CursorPosition = Attributes.defineBindableInt Editor.CursorPositionProperty @@ -48,10 +51,19 @@ module EditorBuilders = /// Create an Editor widget with a text and listen for text changes /// The text value /// Message to dispatch - static member inline Editor<'msg>(text: string, onTextChanged: string -> 'msg) = + static member inline Editor(text: string, onTextChanged: string -> 'msg) = + WidgetBuilder<'msg, IFabEditor>( + Editor.WidgetKey, + InputView.TextWithEventMsg.WithValue(MsgValueEventData.create text (fun (args: TextChangedEventArgs) -> onTextChanged args.NewTextValue)) + ) + + /// Create an Editor widget with a text and listen for text changes + /// The text value + /// Message to dispatch + static member inline Editor(text: string, onTextChanged: string -> unit) = WidgetBuilder<'msg, IFabEditor>( Editor.WidgetKey, - InputView.TextWithEvent.WithValue(ValueEventData.create text (fun (args: TextChangedEventArgs) -> onTextChanged args.NewTextValue)) + InputView.TextWithEventFn.WithValue(ValueEventData.create text (fun (args: TextChangedEventArgs) -> onTextChanged args.NewTextValue)) ) [] @@ -125,7 +137,14 @@ type EditorModifiers = /// Message to dispatch [] static member inline onCompleted(this: WidgetBuilder<'msg, #IFabEditor>, msg: 'msg) = - this.AddScalar(Editor.Completed.WithValue(MsgValue(msg))) + this.AddScalar(Editor.CompletedMsg.WithValue(MsgValue(msg))) + + /// Listen for the Completed event + /// Current widget + /// Function to execute + [] + static member inline onCompleted(this: WidgetBuilder<'msg, #IFabEditor>, fn: unit -> unit) = + this.AddScalar(Editor.CompletedFn.WithValue(fn)) /// Set the selection length /// Current widget diff --git a/src/Fabulous.MauiControls/Views/Controls/Entry.fs b/src/Fabulous.MauiControls/Views/Controls/Entry.fs index a35e409..ff9f890 100644 --- a/src/Fabulous.MauiControls/Views/Controls/Entry.fs +++ b/src/Fabulous.MauiControls/Views/Controls/Entry.fs @@ -16,8 +16,11 @@ module Entry = let ClearButtonVisibility = Attributes.defineBindableEnum Entry.ClearButtonVisibilityProperty - let Completed = - Attributes.defineEventNoArg "Entry_Completed" (fun target -> (target :?> Entry).Completed) + let CompletedMsg = + Attributes.defineEventNoArg "Entry_CompletedMsg" (fun target -> (target :?> Entry).Completed) + + let CompletedFn = + Attributes.defineEventNoArgNoDispatch "Entry_CompletedFn" (fun target -> (target :?> Entry).Completed) let CursorPosition = Attributes.defineBindableInt Entry.CursorPositionProperty @@ -66,10 +69,19 @@ module EntryBuilders = /// Create an Entry widget with a text and listen for text changes /// The text value /// Message to dispatch - static member inline Entry<'msg>(text: string, onTextChanged: string -> 'msg) = + static member inline Entry(text: string, onTextChanged: string -> 'msg) = + WidgetBuilder<'msg, IFabEntry>( + Entry.WidgetKey, + InputView.TextWithEventMsg.WithValue(MsgValueEventData.create text (fun (args: TextChangedEventArgs) -> onTextChanged args.NewTextValue)) + ) + + /// Create an Entry widget with a text and listen for text changes + /// The text value + /// Message to dispatch + static member inline Entry(text: string, onTextChanged: string -> unit) = WidgetBuilder<'msg, IFabEntry>( Entry.WidgetKey, - InputView.TextWithEvent.WithValue(ValueEventData.create text (fun (args: TextChangedEventArgs) -> onTextChanged args.NewTextValue)) + InputView.TextWithEventFn.WithValue(ValueEventData.create text (fun (args: TextChangedEventArgs) -> onTextChanged args.NewTextValue)) ) [] @@ -150,7 +162,14 @@ type EntryModifiers = /// Message to dispatch [] static member inline onCompleted(this: WidgetBuilder<'msg, #IFabEntry>, msg: 'msg) = - this.AddScalar(Entry.Completed.WithValue(MsgValue(msg))) + this.AddScalar(Entry.CompletedMsg.WithValue(MsgValue(msg))) + + /// Listen for the Completed event + /// Current widget + /// Function to execute + [] + static member inline onCompleted(this: WidgetBuilder<'msg, #IFabEntry>, fn: unit -> unit) = + this.AddScalar(Entry.CompletedFn.WithValue(fn)) /// Set the return type of the keyboard /// Current widget diff --git a/src/Fabulous.MauiControls/Views/Controls/FormattedLabel.fs b/src/Fabulous.MauiControls/Views/Controls/FormattedLabel.fs index f528882..eb297b8 100644 --- a/src/Fabulous.MauiControls/Views/Controls/FormattedLabel.fs +++ b/src/Fabulous.MauiControls/Views/Controls/FormattedLabel.fs @@ -25,7 +25,7 @@ module FormattedLabelBuilders = type Fabulous.Maui.View with /// Create a FormattedLabel widget - static member inline FormattedLabel<'msg>() = + static member inline FormattedLabel() = CollectionBuilder<'msg, IFabFormattedLabel, IFabSpan>(FormattedLabel.WidgetKey, FormattedLabel.Spans) [] diff --git a/src/Fabulous.MauiControls/Views/Controls/GraphicsView.fs b/src/Fabulous.MauiControls/Views/Controls/GraphicsView.fs index a17e3bb..1abfd1e 100644 --- a/src/Fabulous.MauiControls/Views/Controls/GraphicsView.fs +++ b/src/Fabulous.MauiControls/Views/Controls/GraphicsView.fs @@ -11,29 +11,50 @@ type IGraphicsView = module GraphicsView = let WidgetKey = Widgets.register() - let CancelInteraction = - Attributes.defineEventNoArg "GraphicsView_CancelInteraction" (fun target -> (target :?> GraphicsView).CancelInteraction) + let CancelInteractionMsg = + Attributes.defineEventNoArg "GraphicsView_CancelInteractionMsg" (fun target -> (target :?> GraphicsView).CancelInteraction) - let DragInteraction = - Attributes.defineEvent "GraphicsView_DragInteraction" (fun target -> (target :?> GraphicsView).DragInteraction) + let CancelInteractionFn = + Attributes.defineEventNoArgNoDispatch "GraphicsView_CancelInteractionFn" (fun target -> (target :?> GraphicsView).CancelInteraction) + + let DragInteractionMsg = + Attributes.defineEvent "GraphicsView_DragInteractionMsg" (fun target -> (target :?> GraphicsView).DragInteraction) + + let DragInteractionFn = + Attributes.defineEventNoDispatch "GraphicsView_DragInteractionFn" (fun target -> (target :?> GraphicsView).DragInteraction) let Drawable = Attributes.defineBindableWithEquality GraphicsView.DrawableProperty - let EndHoverInteraction = - Attributes.defineEventNoArg "GraphicsView_EndHoverInteraction" (fun target -> (target :?> GraphicsView).EndHoverInteraction) + let EndHoverInteractionMsg = + Attributes.defineEventNoArg "GraphicsView_EndHoverInteractionMsg" (fun target -> (target :?> GraphicsView).EndHoverInteraction) + + let EndHoverInteractionFn = + Attributes.defineEventNoArgNoDispatch "GraphicsView_EndHoverInteractionFn" (fun target -> (target :?> GraphicsView).EndHoverInteraction) + + let EndInteractionMsg = + Attributes.defineEvent "GraphicsView_EndInteractionMsg" (fun target -> (target :?> GraphicsView).EndInteraction) + + let EndInteractionFn = + Attributes.defineEventNoDispatch "GraphicsView_EndInteractionFn" (fun target -> (target :?> GraphicsView).EndInteraction) - let EndInteraction = - Attributes.defineEvent "GraphicsView_EndInteraction" (fun target -> (target :?> GraphicsView).EndInteraction) + let MoveHoverInteractionMsg = + Attributes.defineEvent "GraphicsView_MoveHoverInteractionMsg" (fun target -> (target :?> GraphicsView).MoveHoverInteraction) - let MoveHoverInteraction = - Attributes.defineEvent "GraphicsView_MoveHoverInteraction" (fun target -> (target :?> GraphicsView).MoveHoverInteraction) + let MoveHoverInteractionFn = + Attributes.defineEventNoDispatch "GraphicsView_MoveHoverInteractionFn" (fun target -> (target :?> GraphicsView).MoveHoverInteraction) - let StartHoverInteraction = - Attributes.defineEvent "GraphicsView_StartHoverInteraction" (fun target -> (target :?> GraphicsView).StartHoverInteraction) + let StartHoverInteractionMsg = + Attributes.defineEvent "GraphicsView_StartHoverInteractionMsg" (fun target -> (target :?> GraphicsView).StartHoverInteraction) - let StartInteraction = - Attributes.defineEvent "GraphicsView_StartInteraction" (fun target -> (target :?> GraphicsView).StartInteraction) + let StartHoverInteractionFn = + Attributes.defineEventNoDispatch "GraphicsView_StartHoverInteractionFn" (fun target -> (target :?> GraphicsView).StartHoverInteraction) + + let StartInteractionMsg = + Attributes.defineEvent "GraphicsView_StartInteractionMsg" (fun target -> (target :?> GraphicsView).StartInteraction) + + let StartInteractionFn = + Attributes.defineEventNoDispatch "GraphicsView_StartInteractionFn" (fun target -> (target :?> GraphicsView).StartInteraction) [] module GraphicsViewBuilders = @@ -42,7 +63,7 @@ module GraphicsViewBuilders = /// Create a GraphicsView widget with a drawable content /// The drawable content - static member inline GraphicsView<'msg>(drawable: IDrawable) = + static member inline GraphicsView(drawable: IDrawable) = WidgetBuilder<'msg, IGraphicsView>(GraphicsView.WidgetKey, GraphicsView.Drawable.WithValue(drawable)) [] @@ -52,46 +73,95 @@ type GraphicsViewModifiers = /// Message to dispatch [] static member inline onCancelInteraction(this: WidgetBuilder<'msg, #IGraphicsView>, msg: 'msg) = - this.AddScalar(GraphicsView.CancelInteraction.WithValue(MsgValue(msg))) + this.AddScalar(GraphicsView.CancelInteractionMsg.WithValue(MsgValue(msg))) + + /// Listen for the CancelInteraction event, which is raised when the press that made contact with the GraphicsView loses contact + /// Current widget + /// Function to execute + [] + static member inline onCancelInteraction(this: WidgetBuilder<'msg, #IGraphicsView>, fn: unit -> unit) = + this.AddScalar(GraphicsView.CancelInteractionFn.WithValue(fn)) /// Listen for the DragInteraction event, with TouchEventArgs, which is raised when the GraphicsView is dragged /// Current widget /// Message to dispatch [] static member inline onDragInteraction(this: WidgetBuilder<'msg, #IGraphicsView>, fn: TouchEventArgs -> 'msg) = - this.AddScalar(GraphicsView.DragInteraction.WithValue(fun args -> fn args |> box)) + this.AddScalar(GraphicsView.DragInteractionMsg.WithValue(fun args -> fn args |> box)) + + /// Listen for the DragInteraction event, with TouchEventArgs, which is raised when the GraphicsView is dragged + /// Current widget + /// Message to dispatch + [] + static member inline onDragInteraction(this: WidgetBuilder<'msg, #IGraphicsView>, fn: TouchEventArgs -> unit) = + this.AddScalar(GraphicsView.DragInteractionFn.WithValue(fn)) /// Listen for the EndHoverInteraction event, which is raised when a pointer leaves the hit test area of the GraphicsView /// Current widget /// Message to dispatch [] static member inline onEndHoverInteraction(this: WidgetBuilder<'msg, #IGraphicsView>, msg: 'msg) = - this.AddScalar(GraphicsView.EndHoverInteraction.WithValue(MsgValue(msg))) + this.AddScalar(GraphicsView.EndHoverInteractionMsg.WithValue(MsgValue(msg))) + + /// Listen for the EndHoverInteraction event, which is raised when a pointer leaves the hit test area of the GraphicsView + /// Current widget + /// Function to execute + [] + static member inline onEndHoverInteraction(this: WidgetBuilder<'msg, #IGraphicsView>, fn: unit -> unit) = + this.AddScalar(GraphicsView.EndHoverInteractionFn.WithValue(fn)) /// Listen for the EndInteraction event, with TouchEventArgs, which is raised when the press that raised the StartInteraction event is released /// Current widget /// Message to dispatch [] static member inline onEndInteraction(this: WidgetBuilder<'msg, #IGraphicsView>, fn: TouchEventArgs -> 'msg) = - this.AddScalar(GraphicsView.EndInteraction.WithValue(fun args -> fn args |> box)) + this.AddScalar(GraphicsView.EndInteractionMsg.WithValue(fun args -> fn args |> box)) + + /// Listen for the EndInteraction event, with TouchEventArgs, which is raised when the press that raised the StartInteraction event is released + /// Current widget + /// Message to dispatch + [] + static member inline onEndInteraction(this: WidgetBuilder<'msg, #IGraphicsView>, fn: TouchEventArgs -> unit) = + this.AddScalar(GraphicsView.EndInteractionFn.WithValue(fn)) /// Listen for the MoveHoverInteraction event, with TouchEventArgs, which is raised when a pointer moves while the pointer remains within the hit test area of the GraphicsView /// Current widget /// Message to dispatch [] static member inline onMoveHoverInteraction(this: WidgetBuilder<'msg, #IGraphicsView>, fn: TouchEventArgs -> 'msg) = - this.AddScalar(GraphicsView.MoveHoverInteraction.WithValue(fun args -> fn args |> box)) + this.AddScalar(GraphicsView.MoveHoverInteractionMsg.WithValue(fun args -> fn args |> box)) + + /// Listen for the MoveHoverInteraction event, with TouchEventArgs, which is raised when a pointer moves while the pointer remains within the hit test area of the GraphicsView + /// Current widget + /// Message to dispatch + [] + static member inline onMoveHoverInteraction(this: WidgetBuilder<'msg, #IGraphicsView>, fn: TouchEventArgs -> unit) = + this.AddScalar(GraphicsView.MoveHoverInteractionFn.WithValue(fn)) /// Listen for the StartHoverInteraction event, with TouchEventArgs, which is raised when a pointer enters the hit test area of the GraphicsView /// Current widget /// Message to dispatch [] static member inline onStartHoverInteraction(this: WidgetBuilder<'msg, #IGraphicsView>, fn: TouchEventArgs -> 'msg) = - this.AddScalar(GraphicsView.StartHoverInteraction.WithValue(fun args -> fn args |> box)) + this.AddScalar(GraphicsView.StartHoverInteractionMsg.WithValue(fun args -> fn args |> box)) + + /// Listen for the StartHoverInteraction event, with TouchEventArgs, which is raised when a pointer enters the hit test area of the GraphicsView + /// Current widget + /// Message to dispatch + [] + static member inline onStartHoverInteraction(this: WidgetBuilder<'msg, #IGraphicsView>, fn: TouchEventArgs -> unit) = + this.AddScalar(GraphicsView.StartHoverInteractionFn.WithValue(fn)) /// Listen for the StartInteraction event, with TouchEventArgs, which is raised when the GraphicsView is pressed /// Current widget /// Message to dispatch [] static member inline onStartInteraction(this: WidgetBuilder<'msg, #IGraphicsView>, fn: TouchEventArgs -> 'msg) = - this.AddScalar(GraphicsView.StartInteraction.WithValue(fun args -> fn args |> box)) + this.AddScalar(GraphicsView.StartInteractionMsg.WithValue(fun args -> fn args |> box)) + + /// Listen for the StartInteraction event, with TouchEventArgs, which is raised when the GraphicsView is pressed + /// Current widget + /// Message to dispatch + [] + static member inline onStartInteraction(this: WidgetBuilder<'msg, #IGraphicsView>, fn: TouchEventArgs -> unit) = + this.AddScalar(GraphicsView.StartInteractionFn.WithValue(fn)) diff --git a/src/Fabulous.MauiControls/Views/Controls/Image.fs b/src/Fabulous.MauiControls/Views/Controls/Image.fs index be17bd6..e63296f 100644 --- a/src/Fabulous.MauiControls/Views/Controls/Image.fs +++ b/src/Fabulous.MauiControls/Views/Controls/Image.fs @@ -30,46 +30,46 @@ module ImageBuilders = /// Create an Image widget with a source /// The image source - static member inline Image<'msg>(source: ImageSource) = + static member inline Image(source: ImageSource) = WidgetBuilder<'msg, IFabImage>(Image.WidgetKey, Image.Source.WithValue(ImageSourceValue.Source source)) /// Create an Image widget with a source and an aspect /// The image source /// The image aspect - static member inline Image<'msg>(source: ImageSource, aspect: Aspect) = + static member inline Image(source: ImageSource, aspect: Aspect) = WidgetBuilder<'msg, IFabImage>(Image.WidgetKey, Image.Source.WithValue(ImageSourceValue.Source source), Image.Aspect.WithValue(aspect)) /// Create an Image widget with a source /// The image source - static member inline Image<'msg>(source: string) = + static member inline Image(source: string) = WidgetBuilder<'msg, IFabImage>(Image.WidgetKey, Image.Source.WithValue(ImageSourceValue.File source)) /// Create an Image widget with a source and an aspect /// The image source /// The image aspect - static member inline Image<'msg>(source: string, aspect: Aspect) = + static member inline Image(source: string, aspect: Aspect) = WidgetBuilder<'msg, IFabImage>(Image.WidgetKey, Image.Source.WithValue(ImageSourceValue.File source), Image.Aspect.WithValue(aspect)) /// Create an Image widget with a source /// The image source - static member inline Image<'msg>(source: Uri) = + static member inline Image(source: Uri) = WidgetBuilder<'msg, IFabImage>(Image.WidgetKey, Image.Source.WithValue(ImageSourceValue.Uri source)) /// Create an Image widget with a source and an aspect /// The image source /// The image aspect - static member inline Image<'msg>(source: Uri, aspect: Aspect) = + static member inline Image(source: Uri, aspect: Aspect) = WidgetBuilder<'msg, IFabImage>(Image.WidgetKey, Image.Source.WithValue(ImageSourceValue.Uri source), Image.Aspect.WithValue(aspect)) /// Create an Image widget with a source /// The image source - static member inline Image<'msg>(source: Stream) = + static member inline Image(source: Stream) = WidgetBuilder<'msg, IFabImage>(Image.WidgetKey, Image.Source.WithValue(ImageSourceValue.Stream source)) /// Create an Image widget with a source and an aspect /// The image source /// The image aspect - static member inline Image<'msg>(source: Stream, aspect: Aspect) = + static member inline Image(source: Stream, aspect: Aspect) = WidgetBuilder<'msg, IFabImage>(Image.WidgetKey, Image.Source.WithValue(ImageSourceValue.Stream source), Image.Aspect.WithValue(aspect)) [] diff --git a/src/Fabulous.MauiControls/Views/Controls/ImageButton.fs b/src/Fabulous.MauiControls/Views/Controls/ImageButton.fs index 29ed6e3..d790591 100644 --- a/src/Fabulous.MauiControls/Views/Controls/ImageButton.fs +++ b/src/Fabulous.MauiControls/Views/Controls/ImageButton.fs @@ -21,8 +21,11 @@ module ImageButton = let BorderWidth = Attributes.defineBindableFloat ImageButton.BorderWidthProperty - let Clicked = - Attributes.defineEventNoArg "ImageButton_Clicked" (fun target -> (target :?> ImageButton).Clicked) + let ClickedMsg = + Attributes.defineEventNoArg "ImageButton_ClickedMsg" (fun target -> (target :?> ImageButton).Clicked) + + let ClickedFn = + Attributes.defineEventNoArgNoDispatch "ImageButton_ClickedFn" (fun target -> (target :?> ImageButton).Clicked) let CornerRadius = Attributes.defineBindableFloat ImageButton.CornerRadiusProperty @@ -35,11 +38,17 @@ module ImageButton = let Padding = Attributes.defineBindableWithEquality ImageButton.PaddingProperty - let Pressed = - Attributes.defineEventNoArg "ImageButton_Pressed" (fun target -> (target :?> ImageButton).Pressed) + let PressedMsg = + Attributes.defineEventNoArg "ImageButton_PressedMsg" (fun target -> (target :?> ImageButton).Pressed) + + let PressedFn = + Attributes.defineEventNoArgNoDispatch "ImageButton_PressedFn" (fun target -> (target :?> ImageButton).Pressed) + + let ReleasedMsg = + Attributes.defineEventNoArg "ImageButton_ReleasedMsg" (fun target -> (target :?> ImageButton).Released) - let Released = - Attributes.defineEventNoArg "ImageButton_Released" (fun target -> (target :?> ImageButton).Released) + let ReleasedFn = + Attributes.defineEventNoArgNoDispatch "ImageButton_ReleasedFn" (fun target -> (target :?> ImageButton).Released) let Source = Attributes.defineBindableImageSource ImageButton.SourceProperty @@ -50,10 +59,10 @@ module ImageButtonBuilders = /// Create an ImageButton with an image source and listen for the Click event /// The image source /// Message to dispatch - static member inline ImageButton<'msg>(source: ImageSource, onClicked: 'msg) = + static member inline ImageButton(source: ImageSource, onClicked: 'msg) = WidgetBuilder<'msg, IFabImageButton>( ImageButton.WidgetKey, - ImageButton.Clicked.WithValue(MsgValue(onClicked)), + ImageButton.ClickedMsg.WithValue(MsgValue(onClicked)), ImageButton.Source.WithValue(ImageSourceValue.Source source) ) @@ -61,10 +70,10 @@ module ImageButtonBuilders = /// The image source /// Message to dispatch /// The aspect value - static member inline ImageButton<'msg>(source: ImageSource, onClicked: 'msg, aspect: Aspect) = + static member inline ImageButton(source: ImageSource, onClicked: 'msg, aspect: Aspect) = WidgetBuilder<'msg, IFabImageButton>( ImageButton.WidgetKey, - ImageButton.Clicked.WithValue(MsgValue(onClicked)), + ImageButton.ClickedMsg.WithValue(MsgValue(onClicked)), ImageButton.Source.WithValue(ImageSourceValue.Source source), ImageButton.Aspect.WithValue(aspect) ) @@ -72,10 +81,10 @@ module ImageButtonBuilders = /// Create an ImageButton with an image source and listen for the Click event /// The image source /// Message to dispatch - static member inline ImageButton<'msg>(source: string, onClicked: 'msg) = + static member inline ImageButton(source: string, onClicked: 'msg) = WidgetBuilder<'msg, IFabImageButton>( ImageButton.WidgetKey, - ImageButton.Clicked.WithValue(MsgValue(onClicked)), + ImageButton.ClickedMsg.WithValue(MsgValue(onClicked)), ImageButton.Source.WithValue(ImageSourceValue.File source) ) @@ -83,10 +92,10 @@ module ImageButtonBuilders = /// The image source /// Message to dispatch /// The aspect value - static member inline ImageButton<'msg>(source: string, onClicked: 'msg, aspect: Aspect) = + static member inline ImageButton(source: string, onClicked: 'msg, aspect: Aspect) = WidgetBuilder<'msg, IFabImageButton>( ImageButton.WidgetKey, - ImageButton.Clicked.WithValue(MsgValue(onClicked)), + ImageButton.ClickedMsg.WithValue(MsgValue(onClicked)), ImageButton.Source.WithValue(ImageSourceValue.File source), ImageButton.Aspect.WithValue(aspect) ) @@ -94,10 +103,10 @@ module ImageButtonBuilders = /// Create an ImageButton with an image source and listen for the Click event /// The image source /// Message to dispatch - static member inline ImageButton<'msg>(source: Uri, onClicked: 'msg) = + static member inline ImageButton(source: Uri, onClicked: 'msg) = WidgetBuilder<'msg, IFabImageButton>( ImageButton.WidgetKey, - ImageButton.Clicked.WithValue(MsgValue(onClicked)), + ImageButton.ClickedMsg.WithValue(MsgValue(onClicked)), ImageButton.Source.WithValue(ImageSourceValue.Uri source) ) @@ -105,10 +114,10 @@ module ImageButtonBuilders = /// The image source /// Message to dispatch /// The aspect value - static member inline ImageButton<'msg>(source: Uri, onClicked: 'msg, aspect: Aspect) = + static member inline ImageButton(source: Uri, onClicked: 'msg, aspect: Aspect) = WidgetBuilder<'msg, IFabImageButton>( ImageButton.WidgetKey, - ImageButton.Clicked.WithValue(MsgValue(onClicked)), + ImageButton.ClickedMsg.WithValue(MsgValue(onClicked)), ImageButton.Source.WithValue(ImageSourceValue.Uri source), ImageButton.Aspect.WithValue(aspect) ) @@ -116,10 +125,10 @@ module ImageButtonBuilders = /// Create an ImageButton with an image source and listen for the Click event /// The image source /// Message to dispatch - static member inline ImageButton<'msg>(source: Stream, onClicked: 'msg) = + static member inline ImageButton(source: Stream, onClicked: 'msg) = WidgetBuilder<'msg, IFabImageButton>( ImageButton.WidgetKey, - ImageButton.Clicked.WithValue(MsgValue(onClicked)), + ImageButton.ClickedMsg.WithValue(MsgValue(onClicked)), ImageButton.Source.WithValue(ImageSourceValue.Stream source) ) @@ -127,10 +136,98 @@ module ImageButtonBuilders = /// The image source /// Message to dispatch /// The aspect value - static member inline ImageButton<'msg>(source: Stream, onClicked: 'msg, aspect: Aspect) = + static member inline ImageButton(source: Stream, onClicked: 'msg, aspect: Aspect) = WidgetBuilder<'msg, IFabImageButton>( ImageButton.WidgetKey, - ImageButton.Clicked.WithValue(MsgValue(onClicked)), + ImageButton.ClickedMsg.WithValue(MsgValue(onClicked)), + ImageButton.Source.WithValue(ImageSourceValue.Stream source), + ImageButton.Aspect.WithValue(aspect) + ) + + /// Create an ImageButton with an image source and listen for the Click event + /// The image source + /// Message to dispatch + static member inline ImageButton(source: ImageSource, onClicked: unit -> unit) = + WidgetBuilder<'msg, IFabImageButton>( + ImageButton.WidgetKey, + ImageButton.ClickedFn.WithValue(onClicked), + ImageButton.Source.WithValue(ImageSourceValue.Source source) + ) + + /// Create an ImageButton with an image source and an aspect and listen for the Click event + /// The image source + /// Message to dispatch + /// The aspect value + static member inline ImageButton(source: ImageSource, onClicked: unit -> unit, aspect: Aspect) = + WidgetBuilder<'msg, IFabImageButton>( + ImageButton.WidgetKey, + ImageButton.ClickedFn.WithValue(onClicked), + ImageButton.Source.WithValue(ImageSourceValue.Source source), + ImageButton.Aspect.WithValue(aspect) + ) + + /// Create an ImageButton with an image source and listen for the Click event + /// The image source + /// Message to dispatch + static member inline ImageButton(source: string, onClicked: unit -> unit) = + WidgetBuilder<'msg, IFabImageButton>( + ImageButton.WidgetKey, + ImageButton.ClickedFn.WithValue(onClicked), + ImageButton.Source.WithValue(ImageSourceValue.File source) + ) + + /// Create an ImageButton with an image source and an aspect and listen for the Click event + /// The image source + /// Message to dispatch + /// The aspect value + static member inline ImageButton(source: string, onClicked: unit -> unit, aspect: Aspect) = + WidgetBuilder<'msg, IFabImageButton>( + ImageButton.WidgetKey, + ImageButton.ClickedFn.WithValue(onClicked), + ImageButton.Source.WithValue(ImageSourceValue.File source), + ImageButton.Aspect.WithValue(aspect) + ) + + /// Create an ImageButton with an image source and listen for the Click event + /// The image source + /// Message to dispatch + static member inline ImageButton(source: Uri, onClicked: unit -> unit) = + WidgetBuilder<'msg, IFabImageButton>( + ImageButton.WidgetKey, + ImageButton.ClickedFn.WithValue(onClicked), + ImageButton.Source.WithValue(ImageSourceValue.Uri source) + ) + + /// Create an ImageButton with an image source and an aspect and listen for the Click event + /// The image source + /// Message to dispatch + /// The aspect value + static member inline ImageButton(source: Uri, onClicked: unit -> unit, aspect: Aspect) = + WidgetBuilder<'msg, IFabImageButton>( + ImageButton.WidgetKey, + ImageButton.ClickedFn.WithValue(onClicked), + ImageButton.Source.WithValue(ImageSourceValue.Uri source), + ImageButton.Aspect.WithValue(aspect) + ) + + /// Create an ImageButton with an image source and listen for the Click event + /// The image source + /// Message to dispatch + static member inline ImageButton(source: Stream, onClicked: unit -> unit) = + WidgetBuilder<'msg, IFabImageButton>( + ImageButton.WidgetKey, + ImageButton.ClickedFn.WithValue(onClicked), + ImageButton.Source.WithValue(ImageSourceValue.Stream source) + ) + + /// Create an ImageButton with an image source and an aspect and listen for the Click event + /// The image source + /// Message to dispatch + /// The aspect value + static member inline ImageButton(source: Stream, onClicked: unit -> unit, aspect: Aspect) = + WidgetBuilder<'msg, IFabImageButton>( + ImageButton.WidgetKey, + ImageButton.ClickedFn.WithValue(onClicked), ImageButton.Source.WithValue(ImageSourceValue.Stream source), ImageButton.Aspect.WithValue(aspect) ) @@ -184,14 +281,28 @@ type ImageButtonModifiers = /// Message to dispatch [] static member inline onPressed(this: WidgetBuilder<'msg, #IFabImageButton>, msg: 'msg) = - this.AddScalar(ImageButton.Pressed.WithValue(MsgValue(msg))) + this.AddScalar(ImageButton.PressedMsg.WithValue(MsgValue(msg))) + + /// Listen for the Pressed event + /// Current widget + /// Function to execute + [] + static member inline onPressed(this: WidgetBuilder<'msg, #IFabImageButton>, fn: unit -> unit) = + this.AddScalar(ImageButton.PressedFn.WithValue(fn)) /// Listen for the Released event /// Current widget /// Message to dispatch [] static member inline onReleased(this: WidgetBuilder<'msg, #IFabImageButton>, msg: 'msg) = - this.AddScalar(ImageButton.Released.WithValue(MsgValue(msg))) + this.AddScalar(ImageButton.ReleasedMsg.WithValue(MsgValue(msg))) + + /// Listen for the Released event + /// Current widget + /// Function to execute + [] + static member inline onReleased(this: WidgetBuilder<'msg, #IFabImageButton>, fn: unit -> unit) = + this.AddScalar(ImageButton.ReleasedFn.WithValue(fn)) /// Set the padding inside the button /// Current widget diff --git a/src/Fabulous.MauiControls/Views/Controls/IndicatorView.fs b/src/Fabulous.MauiControls/Views/Controls/IndicatorView.fs index 78ebc21..b179caf 100644 --- a/src/Fabulous.MauiControls/Views/Controls/IndicatorView.fs +++ b/src/Fabulous.MauiControls/Views/Controls/IndicatorView.fs @@ -43,7 +43,7 @@ module IndicatorViewBuilders = type Fabulous.Maui.View with /// Create an IndicatorView widget with a reference - static member inline IndicatorView<'msg>(reference: ViewRef) = + static member inline IndicatorView(reference: ViewRef) = WidgetBuilder<'msg, IFabIndicatorView>(IndicatorView.WidgetKey, ViewRefAttributes.ViewRef.WithValue(reference.Unbox)) [] diff --git a/src/Fabulous.MauiControls/Views/Controls/Label.fs b/src/Fabulous.MauiControls/Views/Controls/Label.fs index 008c400..20c57e7 100644 --- a/src/Fabulous.MauiControls/Views/Controls/Label.fs +++ b/src/Fabulous.MauiControls/Views/Controls/Label.fs @@ -58,7 +58,7 @@ module LabelBuilders = /// Create a Label widget with a text /// The text value - static member inline Label<'msg>(text: string) = + static member inline Label(text: string) = WidgetBuilder<'msg, IFabLabel>(Label.WidgetKey, Label.Text.WithValue(text)) [] diff --git a/src/Fabulous.MauiControls/Views/Controls/Picker.fs b/src/Fabulous.MauiControls/Views/Controls/Picker.fs index f7f92b9..df057c4 100644 --- a/src/Fabulous.MauiControls/Views/Controls/Picker.fs +++ b/src/Fabulous.MauiControls/Views/Controls/Picker.fs @@ -67,8 +67,12 @@ module Picker = | ValueNone -> target.ClearValue(Picker.ItemsSourceProperty) | ValueSome value -> target.SetValue(Picker.ItemsSourceProperty, value)) - let SelectedIndexWithEvent = - Attributes.defineBindableWithEvent "Picker_SelectedIndexChanged" Picker.SelectedIndexProperty (fun target -> + let SelectedIndexWithEventMsg = + Attributes.defineBindableWithEvent "Picker_SelectedIndexChangedMsg" Picker.SelectedIndexProperty (fun target -> + (target :?> FabPicker).CustomSelectedIndexChanged) + + let SelectedIndexWithEventFn = + Attributes.defineBindableWithEventNoDispatch "Picker_SelectedIndexChangedFn" Picker.SelectedIndexProperty (fun target -> (target :?> FabPicker).CustomSelectedIndexChanged) let TextColor = Attributes.defineBindableColor Picker.TextColorProperty @@ -100,11 +104,24 @@ module PickerBuilders = /// The items list /// The selected index /// Message to dispatch - static member inline Picker<'msg>(items: string list, selectedIndex: int, onSelectedIndexChanged: int -> 'msg) = + static member inline Picker(items: string list, selectedIndex: int, onSelectedIndexChanged: int -> 'msg) = + WidgetBuilder<'msg, IFabPicker>( + Picker.WidgetKey, + Picker.ItemsSource.WithValue(Array.ofList items), + Picker.SelectedIndexWithEventMsg.WithValue( + MsgValueEventData.create selectedIndex (fun (args: PositionChangedEventArgs) -> onSelectedIndexChanged args.CurrentPosition) + ) + ) + + /// Create a Picker widget with a list of items, the selected index and listen to the selected index changes + /// The items list + /// The selected index + /// Message to dispatch + static member inline Picker(items: string list, selectedIndex: int, onSelectedIndexChanged: int -> unit) = WidgetBuilder<'msg, IFabPicker>( Picker.WidgetKey, Picker.ItemsSource.WithValue(Array.ofList items), - Picker.SelectedIndexWithEvent.WithValue( + Picker.SelectedIndexWithEventFn.WithValue( ValueEventData.create selectedIndex (fun (args: PositionChangedEventArgs) -> onSelectedIndexChanged args.CurrentPosition) ) ) diff --git a/src/Fabulous.MauiControls/Views/Controls/ProgressBar.fs b/src/Fabulous.MauiControls/Views/Controls/ProgressBar.fs index eb093d9..c5a968e 100644 --- a/src/Fabulous.MauiControls/Views/Controls/ProgressBar.fs +++ b/src/Fabulous.MauiControls/Views/Controls/ProgressBar.fs @@ -38,14 +38,14 @@ module ProgressBarBuilders = /// Create a ProgressBar widget with a current progress value /// The progress value - static member inline ProgressBar<'msg>(progress: float) = + static member inline ProgressBar(progress: float) = WidgetBuilder<'msg, IFabProgressBar>(ProgressBar.WidgetKey, ProgressBar.Progress.WithValue(progress)) /// Create a ProgressBar widget with a progress value that will animate when changed /// The progress value /// The duration of the animation /// The easing of the animation - static member inline ProgressBar<'msg>(progress: float, duration: int, easing: Easing) = + static member inline ProgressBar(progress: float, duration: int, easing: Easing) = WidgetBuilder<'msg, IFabProgressBar>( ProgressBar.WidgetKey, ProgressBarAnimations.ProgressTo.WithValue( diff --git a/src/Fabulous.MauiControls/Views/Controls/RadioButton.fs b/src/Fabulous.MauiControls/Views/Controls/RadioButton.fs index fab19eb..d8ad875 100644 --- a/src/Fabulous.MauiControls/Views/Controls/RadioButton.fs +++ b/src/Fabulous.MauiControls/Views/Controls/RadioButton.fs @@ -41,8 +41,11 @@ module RadioButton = let GroupName = Attributes.defineBindableWithEquality RadioButton.GroupNameProperty - let IsCheckedWithEvent = - Attributes.defineBindableWithEvent "RadioButton_CheckedChanged" RadioButton.IsCheckedProperty (fun target -> (target :?> RadioButton).CheckedChanged) + let IsCheckedWithEventMsg = + Attributes.defineBindableWithEvent "RadioButton_CheckedChangedMsg" RadioButton.IsCheckedProperty (fun target -> (target :?> RadioButton).CheckedChanged) + + let IsCheckedWithEventFn = + Attributes.defineBindableWithEventNoDispatch "RadioButton_CheckedChangedFn" RadioButton.IsCheckedProperty (fun target -> (target :?> RadioButton).CheckedChanged) let TextColor = Attributes.defineBindableColor RadioButton.TextColorProperty @@ -61,10 +64,21 @@ module RadioButtonBuilders = /// The content /// The checked state /// Message to dispatch - static member inline RadioButton<'msg>(content: string, isChecked: bool, onChecked: bool -> 'msg) = + static member inline RadioButton(content: string, isChecked: bool, onChecked: bool -> 'msg) = + WidgetBuilder<'msg, IFabRadioButton>( + RadioButton.WidgetKey, + RadioButton.IsCheckedWithEventMsg.WithValue(MsgValueEventData.create isChecked (fun (args: CheckedChangedEventArgs) -> onChecked args.Value)), + RadioButton.ContentString.WithValue(content) + ) + + /// Create a RadioButton widget with a content, a checked state and listen for the checked state changes + /// The content + /// The checked state + /// Message to dispatch + static member inline RadioButton(content: string, isChecked: bool, onChecked: bool -> unit) = WidgetBuilder<'msg, IFabRadioButton>( RadioButton.WidgetKey, - RadioButton.IsCheckedWithEvent.WithValue(ValueEventData.create isChecked (fun (args: CheckedChangedEventArgs) -> onChecked args.Value)), + RadioButton.IsCheckedWithEventFn.WithValue(ValueEventData.create isChecked (fun (args: CheckedChangedEventArgs) -> onChecked args.Value)), RadioButton.ContentString.WithValue(content) ) @@ -77,7 +91,23 @@ module RadioButtonBuilders = RadioButton.WidgetKey, AttributesBundle( StackList.one( - RadioButton.IsCheckedWithEvent.WithValue(ValueEventData.create isChecked (fun (args: CheckedChangedEventArgs) -> onChecked args.Value)) + RadioButton.IsCheckedWithEventMsg.WithValue(MsgValueEventData.create isChecked (fun (args: CheckedChangedEventArgs) -> onChecked args.Value)) + ), + ValueSome [| RadioButton.ContentWidget.WithValue(content.Compile()) |], + ValueNone + ) + ) + + /// Create a RadioButton widget with a content, a checked state and listen for the checked state changes + /// The content widget + /// The checked state + /// Message to dispatch + static member inline RadioButton(content: WidgetBuilder<'msg, #IFabView>, isChecked: bool, onChecked: bool -> unit) = + WidgetBuilder<'msg, IFabRadioButton>( + RadioButton.WidgetKey, + AttributesBundle( + StackList.one( + RadioButton.IsCheckedWithEventFn.WithValue(ValueEventData.create isChecked (fun (args: CheckedChangedEventArgs) -> onChecked args.Value)) ), ValueSome [| RadioButton.ContentWidget.WithValue(content.Compile()) |], ValueNone diff --git a/src/Fabulous.MauiControls/Views/Controls/SearchBar.fs b/src/Fabulous.MauiControls/Views/Controls/SearchBar.fs index c144252..05bba0e 100644 --- a/src/Fabulous.MauiControls/Views/Controls/SearchBar.fs +++ b/src/Fabulous.MauiControls/Views/Controls/SearchBar.fs @@ -34,8 +34,11 @@ module SearchBar = let IsTextPredictionEnabled = Attributes.defineBindableBool SearchBar.IsTextPredictionEnabledProperty - let SearchButtonPressed = - Attributes.defineEventNoArg "SearchBar_SearchButtonPressed" (fun target -> (target :?> SearchBar).SearchButtonPressed) + let SearchButtonPressedMsg = + Attributes.defineEventNoArg "SearchBar_SearchButtonPressedMsg" (fun target -> (target :?> SearchBar).SearchButtonPressed) + + let SearchButtonPressedFn = + Attributes.defineEventNoArgNoDispatch "SearchBar_SearchButtonPressedFn" (fun target -> (target :?> SearchBar).SearchButtonPressed) let SelectionLength = Attributes.defineBindableInt SearchBar.SelectionLengthProperty @@ -50,11 +53,22 @@ module SearchBarBuilders = /// The text value /// Message to dispatch /// Message to dispatch - static member inline SearchBar<'msg>(text: string, onTextChanged: string -> 'msg, onSearchButtonPressed: 'msg) = + static member inline SearchBar(text: string, onTextChanged: string -> 'msg, onSearchButtonPressed: 'msg) = + WidgetBuilder<'msg, IFabSearchBar>( + SearchBar.WidgetKey, + InputView.TextWithEventMsg.WithValue(MsgValueEventData.create text (fun (args: TextChangedEventArgs) -> onTextChanged args.NewTextValue)), + SearchBar.SearchButtonPressedMsg.WithValue(MsgValue(onSearchButtonPressed)) + ) + + /// Create a SearchBar widget with a text and listen for both text changes and search button presses + /// The text value + /// Message to dispatch + /// Message to dispatch + static member inline SearchBar(text: string, onTextChanged: string -> unit, onSearchButtonPressed: unit -> unit) = WidgetBuilder<'msg, IFabSearchBar>( SearchBar.WidgetKey, - InputView.TextWithEvent.WithValue(ValueEventData.create text (fun (args: TextChangedEventArgs) -> onTextChanged args.NewTextValue)), - SearchBar.SearchButtonPressed.WithValue(MsgValue(onSearchButtonPressed)) + InputView.TextWithEventFn.WithValue(ValueEventData.create text (fun (args: TextChangedEventArgs) -> onTextChanged args.NewTextValue)), + SearchBar.SearchButtonPressedFn.WithValue(onSearchButtonPressed) ) [] diff --git a/src/Fabulous.MauiControls/Views/Controls/Slider.fs b/src/Fabulous.MauiControls/Views/Controls/Slider.fs index b6dab16..97a30b8 100644 --- a/src/Fabulous.MauiControls/Views/Controls/Slider.fs +++ b/src/Fabulous.MauiControls/Views/Controls/Slider.fs @@ -31,11 +31,17 @@ module SliderUpdaters = module Slider = let WidgetKey = Widgets.register() - let DragCompleted = - Attributes.defineEventNoArg "Slider_DragCompleted" (fun target -> (target :?> Slider).DragCompleted) + let DragCompletedMsg = + Attributes.defineEventNoArg "Slider_DragCompletedMsg" (fun target -> (target :?> Slider).DragCompleted) - let DragStarted = - Attributes.defineEventNoArg "Slider_DragStarted" (fun target -> (target :?> Slider).DragStarted) + let DragCompletedFn = + Attributes.defineEventNoArgNoDispatch "Slider_DragCompletedFn" (fun target -> (target :?> Slider).DragCompleted) + + let DragStartedMsg = + Attributes.defineEventNoArg "Slider_DragStartedMsg" (fun target -> (target :?> Slider).DragStarted) + + let DragStartedFn = + Attributes.defineEventNoArgNoDispatch "Slider_DragStartedFn" (fun target -> (target :?> Slider).DragStarted) let MaximumTrackColor = Attributes.defineBindableColor Slider.MaximumTrackColorProperty @@ -51,8 +57,11 @@ module Slider = let ThumbImageSource = Attributes.defineBindableImageSource Slider.ThumbImageSourceProperty - let ValueWithEvent = - Attributes.defineBindableWithEvent "Slider_ValueWithEvent" Slider.ValueProperty (fun target -> (target :?> Slider).ValueChanged) + let ValueWithEventMsg = + Attributes.defineBindableWithEvent "Slider_ValueWithEventMsg" Slider.ValueProperty (fun target -> (target :?> Slider).ValueChanged) + + let ValueWithEventFn = + Attributes.defineBindableWithEventNoDispatch "Slider_ValueWithEventFn" Slider.ValueProperty (fun target -> (target :?> Slider).ValueChanged) [] module SliderBuilders = @@ -63,11 +72,23 @@ module SliderBuilders = /// The maximum bound /// The current value /// Message to dispatch - static member inline Slider<'msg>(min: float, max: float, value: float, onValueChanged: float -> 'msg) = + static member inline Slider(min: float, max: float, value: float, onValueChanged: float -> 'msg) = + WidgetBuilder<'msg, IFabSlider>( + Slider.WidgetKey, + Slider.MinimumMaximum.WithValue(struct (min, max)), + Slider.ValueWithEventMsg.WithValue(MsgValueEventData.create value (fun (args: ValueChangedEventArgs) -> onValueChanged args.NewValue)) + ) + + /// Create a Slider widget with a min/max bounds and a value, listen for the value changes + /// The minimum bound + /// The maximum bound + /// The current value + /// Message to dispatch + static member inline Slider(min: float, max: float, value: float, onValueChanged: float -> unit) = WidgetBuilder<'msg, IFabSlider>( Slider.WidgetKey, Slider.MinimumMaximum.WithValue(struct (min, max)), - Slider.ValueWithEvent.WithValue(ValueEventData.create value (fun (args: ValueChangedEventArgs) -> onValueChanged args.NewValue)) + Slider.ValueWithEventFn.WithValue(ValueEventData.create value (fun (args: ValueChangedEventArgs) -> onValueChanged args.NewValue)) ) [] @@ -77,14 +98,28 @@ type SliderModifiers = /// Message to dispatch [] static member inline onDragCompleted(this: WidgetBuilder<'msg, #IFabSlider>, msg: 'msg) = - this.AddScalar(Slider.DragCompleted.WithValue(MsgValue(msg))) + this.AddScalar(Slider.DragCompletedMsg.WithValue(MsgValue(msg))) + + /// Listen for the DragCompleted event + /// Current widget + /// Function to execute + [] + static member inline onDragCompleted(this: WidgetBuilder<'msg, #IFabSlider>, fn: unit -> unit) = + this.AddScalar(Slider.DragCompletedFn.WithValue(fn)) /// Listen for the DragStarted event /// Current widget /// Message to dispatch [] static member inline onDragStarted(this: WidgetBuilder<'msg, #IFabSlider>, msg: 'msg) = - this.AddScalar(Slider.DragStarted.WithValue(MsgValue(msg))) + this.AddScalar(Slider.DragStartedMsg.WithValue(MsgValue(msg))) + + /// Listen for the DragStarted event + /// Current widget + /// Function to execute + [] + static member inline onDragStarted(this: WidgetBuilder<'msg, #IFabSlider>, fn: unit -> unit) = + this.AddScalar(Slider.DragStartedFn.WithValue(fn)) /// Set the color of the maximum track /// Current widget diff --git a/src/Fabulous.MauiControls/Views/Controls/Span.fs b/src/Fabulous.MauiControls/Views/Controls/Span.fs index c21dc55..4cf28ae 100644 --- a/src/Fabulous.MauiControls/Views/Controls/Span.fs +++ b/src/Fabulous.MauiControls/Views/Controls/Span.fs @@ -49,7 +49,7 @@ module SpanBuilders = /// Create a Span widget with a text /// The text value - static member inline Span<'msg>(text: string) = + static member inline Span(text: string) = WidgetBuilder<'msg, IFabSpan>(Span.WidgetKey, Span.Text.WithValue(text)) [] @@ -100,7 +100,7 @@ type SpanModifiers = /// Set the gesture recognizers /// Current widget [] - static member inline gestureRecognizers<'msg, 'marker when 'marker :> IFabSpan>(this: WidgetBuilder<'msg, 'marker>) = + static member inline gestureRecognizers<'msg, 'marker when 'msg : equality and 'marker :> IFabSpan>(this: WidgetBuilder<'msg, 'marker>) = WidgetHelpers.buildAttributeCollection<'msg, 'marker, IFabGestureRecognizer> Span.GestureRecognizers this /// Set the line height diff --git a/src/Fabulous.MauiControls/Views/Controls/Stepper.fs b/src/Fabulous.MauiControls/Views/Controls/Stepper.fs index 62d0ca4..d72d14a 100644 --- a/src/Fabulous.MauiControls/Views/Controls/Stepper.fs +++ b/src/Fabulous.MauiControls/Views/Controls/Stepper.fs @@ -33,8 +33,11 @@ module Stepper = let MinimumMaximum = Attributes.defineSimpleScalarWithEquality "Stepper_MinimumMaximum" StepperUpdaters.updateStepperMinMax - let ValueWithEvent = - Attributes.defineBindableWithEvent "Stepper_ValueChanged" Stepper.ValueProperty (fun target -> (target :?> Stepper).ValueChanged) + let ValueWithEventMsg = + Attributes.defineBindableWithEvent "Stepper_ValueChangedMsg" Stepper.ValueProperty (fun target -> (target :?> Stepper).ValueChanged) + + let ValueWithEventFn = + Attributes.defineBindableWithEventNoDispatch "Stepper_ValueChangedFn" Stepper.ValueProperty (fun target -> (target :?> Stepper).ValueChanged) [] module StepperBuilders = @@ -45,11 +48,23 @@ module StepperBuilders = /// The maximum value /// The current value /// Message to dispatch - static member inline Stepper<'msg>(min: float, max: float, value: float, onValueChanged: float -> 'msg) = + static member inline Stepper(min: float, max: float, value: float, onValueChanged: float -> 'msg) = + WidgetBuilder<'msg, IFabStepper>( + Stepper.WidgetKey, + Stepper.MinimumMaximum.WithValue(struct (min, max)), + Stepper.ValueWithEventMsg.WithValue(MsgValueEventData.create value (fun (args: ValueChangedEventArgs) -> onValueChanged args.NewValue)) + ) + + /// Create a Stepper widget with min and max values, a current value, and listen for value changes + /// The minimum value + /// The maximum value + /// The current value + /// Message to dispatch + static member inline Stepper(min: float, max: float, value: float, onValueChanged: float -> unit) = WidgetBuilder<'msg, IFabStepper>( Stepper.WidgetKey, Stepper.MinimumMaximum.WithValue(struct (min, max)), - Stepper.ValueWithEvent.WithValue(ValueEventData.create value (fun (args: ValueChangedEventArgs) -> onValueChanged args.NewValue)) + Stepper.ValueWithEventFn.WithValue(ValueEventData.create value (fun (args: ValueChangedEventArgs) -> onValueChanged args.NewValue)) ) [] diff --git a/src/Fabulous.MauiControls/Views/Controls/Switch.fs b/src/Fabulous.MauiControls/Views/Controls/Switch.fs index e4fa7c0..bd5d559 100644 --- a/src/Fabulous.MauiControls/Views/Controls/Switch.fs +++ b/src/Fabulous.MauiControls/Views/Controls/Switch.fs @@ -15,8 +15,11 @@ module Switch = let ThumbColor = Attributes.defineBindableColor Switch.ThumbColorProperty - let IsToggledWithEvent = - Attributes.defineBindableWithEvent "Switch_Toggled" Switch.IsToggledProperty (fun target -> (target :?> Switch).Toggled) + let IsToggledWithEventMsg = + Attributes.defineBindableWithEvent "Switch_ToggledMsg" Switch.IsToggledProperty (fun target -> (target :?> Switch).Toggled) + + let IsToggledWithEventFn = + Attributes.defineBindableWithEventNoDispatch "Switch_ToggledFn" Switch.IsToggledProperty (fun target -> (target :?> Switch).Toggled) [] module SwitchBuilders = @@ -25,10 +28,19 @@ module SwitchBuilders = /// Create a Switch widget with a toggle state and listen for toggle state changes /// The toggle state /// Message to dispatch - static member inline Switch<'msg>(isToggled: bool, onToggled: bool -> 'msg) = + static member inline Switch(isToggled: bool, onToggled: bool -> 'msg) = + WidgetBuilder<'msg, IFabSwitch>( + Switch.WidgetKey, + Switch.IsToggledWithEventMsg.WithValue(MsgValueEventData.create isToggled (fun (args: ToggledEventArgs) -> onToggled args.Value)) + ) + + /// Create a Switch widget with a toggle state and listen for toggle state changes + /// The toggle state + /// Message to dispatch + static member inline Switch(isToggled: bool, onToggled: bool -> unit) = WidgetBuilder<'msg, IFabSwitch>( Switch.WidgetKey, - Switch.IsToggledWithEvent.WithValue(ValueEventData.create isToggled (fun (args: ToggledEventArgs) -> onToggled args.Value)) + Switch.IsToggledWithEventFn.WithValue(ValueEventData.create isToggled (fun (args: ToggledEventArgs) -> onToggled args.Value)) ) [] diff --git a/src/Fabulous.MauiControls/Views/Controls/TimePicker.fs b/src/Fabulous.MauiControls/Views/Controls/TimePicker.fs index 58569c3..a14e94e 100644 --- a/src/Fabulous.MauiControls/Views/Controls/TimePicker.fs +++ b/src/Fabulous.MauiControls/Views/Controls/TimePicker.fs @@ -35,8 +35,11 @@ module TimePicker = let CharacterSpacing = Attributes.defineBindableFloat TimePicker.CharacterSpacingProperty - let TimeWithEvent = - Attributes.defineBindableWithEvent "TimePicker_TimeSelected" TimePicker.TimeProperty (fun target -> (target :?> FabTimePicker).TimeSelected) + let TimeWithEventMsg = + Attributes.defineBindableWithEvent "TimePicker_TimeSelectedMsg" TimePicker.TimeProperty (fun target -> (target :?> FabTimePicker).TimeSelected) + + let TimeWithEventFn = + Attributes.defineBindableWithEventNoDispatch "TimePicker_TimeSelectedFn" TimePicker.TimeProperty (fun target -> (target :?> FabTimePicker).TimeSelected) let FontAttributes = Attributes.defineBindableEnum TimePicker.FontAttributesProperty @@ -72,10 +75,19 @@ module TimePickerBuilders = /// Create a TimePicker widget with a selected time and listen for the selected time changes /// The selected time /// Message to dispatch - static member inline TimePicker<'msg>(time: TimeSpan, onTimeSelected: TimeSpan -> 'msg) = + static member inline TimePicker(time: TimeSpan, onTimeSelected: TimeSpan -> 'msg) = + WidgetBuilder<'msg, IFabTimePicker>( + TimePicker.WidgetKey, + TimePicker.TimeWithEventMsg.WithValue(MsgValueEventData.create time (fun (args: TimeSelectedEventArgs) -> onTimeSelected args.NewTime)) + ) + + /// Create a TimePicker widget with a selected time and listen for the selected time changes + /// The selected time + /// Message to dispatch + static member inline TimePicker(time: TimeSpan, onTimeSelected: TimeSpan -> unit) = WidgetBuilder<'msg, IFabTimePicker>( TimePicker.WidgetKey, - TimePicker.TimeWithEvent.WithValue(ValueEventData.create time (fun (args: TimeSelectedEventArgs) -> onTimeSelected args.NewTime)) + TimePicker.TimeWithEventFn.WithValue(ValueEventData.create time (fun (args: TimeSelectedEventArgs) -> onTimeSelected args.NewTime)) ) [] diff --git a/src/Fabulous.MauiControls/Views/Controls/WebView.fs b/src/Fabulous.MauiControls/Views/Controls/WebView.fs index afd77e6..ceae5ce 100644 --- a/src/Fabulous.MauiControls/Views/Controls/WebView.fs +++ b/src/Fabulous.MauiControls/Views/Controls/WebView.fs @@ -20,11 +20,17 @@ module WebView = let Cookies = Attributes.defineBindableWithEquality WebView.CookiesProperty - let Navigated = - Attributes.defineEvent "WebView_Navigated" (fun target -> (target :?> WebView).Navigated) + let NavigatedMsg = + Attributes.defineEvent "WebView_NavigatedMsg" (fun target -> (target :?> WebView).Navigated) - let Navigating = - Attributes.defineEvent "WebView_Navigating" (fun target -> (target :?> WebView).Navigating) + let NavigatedFn = + Attributes.defineEventNoDispatch "WebView_NavigatedFn" (fun target -> (target :?> WebView).Navigated) + + let NavigatingMsg = + Attributes.defineEvent "WebView_NavigatingMsg" (fun target -> (target :?> WebView).Navigating) + + let NavigatingFn = + Attributes.defineEventNoDispatch "WebView_NavigatingFn" (fun target -> (target :?> WebView).Navigating) let Source = Attributes.defineBindableWithEquality WebView.SourceProperty @@ -58,29 +64,29 @@ module WebViewBuilders = /// Create a WebView with a source /// The web source - static member inline WebView<'msg>(source: WebViewSource) = + static member inline WebView(source: WebViewSource) = WidgetBuilder<'msg, IFabWebView>(WebView.WidgetKey, WebView.Source.WithValue(source)) /// Create a WebView with an HTML content /// The HTML content /// The base URL - static member inline WebView<'msg>(html: string, ?baseUrl: string) = + static member inline WebView(html: string, ?baseUrl: string) = let source = match baseUrl with | Some url -> HtmlWebViewSource(Html = html, BaseUrl = url) | None -> HtmlWebViewSource(Html = html) - View.WebView<'msg>(source) + View.WebView(source) /// Create a WebView with a Uri source /// The Uri source - static member inline WebView<'msg>(uri: Uri) = - View.WebView<'msg>(WebViewSource.op_Implicit uri) + static member inline WebView(uri: Uri) = + View.WebView(WebViewSource.op_Implicit uri) /// Create a WebView with a Url source /// The Url source - static member inline WebView<'msg>(url: string) = - View.WebView<'msg>(WebViewSource.op_Implicit url) + static member inline WebView(url: string) = + View.WebView(WebViewSource.op_Implicit url) [] type WebViewModifiers() = @@ -110,14 +116,28 @@ type WebViewModifiers() = /// Message to dispatch [] static member inline onNavigated(this: WidgetBuilder<'msg, #IFabWebView>, fn: WebNavigatedEventArgs -> 'msg) = - this.AddScalar(WebView.Navigated.WithValue(fun args -> fn args |> box)) + this.AddScalar(WebView.NavigatedMsg.WithValue(fun args -> fn args |> box)) + + /// Listen for the Navigated event + /// Current widget + /// Message to dispatch + [] + static member inline onNavigated(this: WidgetBuilder<'msg, #IFabWebView>, fn: WebNavigatedEventArgs -> unit) = + this.AddScalar(WebView.NavigatedFn.WithValue(fn)) /// Listen for the Navigating event /// Current widget /// Message to dispatch [] static member inline onNavigating(this: WidgetBuilder<'msg, #IFabWebView>, fn: WebNavigatingEventArgs -> 'msg) = - this.AddScalar(WebView.Navigating.WithValue(fun args -> fn args |> box)) + this.AddScalar(WebView.NavigatingMsg.WithValue(fun args -> fn args |> box)) + + /// Listen for the Navigating event + /// Current widget + /// Message to dispatch + [] + static member inline onNavigating(this: WidgetBuilder<'msg, #IFabWebView>, fn: WebNavigatingEventArgs -> unit) = + this.AddScalar(WebView.NavigatingFn.WithValue(fn)) /// Link a ViewRef to access the direct WebView control instance /// Current widget diff --git a/src/Fabulous.MauiControls/Views/Controls/_InputView.fs b/src/Fabulous.MauiControls/Views/Controls/_InputView.fs index ad205d8..19e862e 100644 --- a/src/Fabulous.MauiControls/Views/Controls/_InputView.fs +++ b/src/Fabulous.MauiControls/Views/Controls/_InputView.fs @@ -34,8 +34,12 @@ module InputView = let TextTransform = Attributes.defineBindableEnum InputView.TextTransformProperty - let TextWithEvent = - Attributes.defineBindableWithEvent "InputView_TextChanged" InputView.TextProperty (fun target -> + let TextWithEventMsg = + Attributes.defineBindableWithEvent "InputView_TextChangedMsg" InputView.TextProperty (fun target -> + (target :?> InputView).TextChanged) + + let TextWithEventFn = + Attributes.defineBindableWithEventNoDispatch "InputView_TextChangedFn" InputView.TextProperty (fun target -> (target :?> InputView).TextChanged) [] diff --git a/src/Fabulous.MauiControls/Views/GestureRecognizers/DragGestureRecognizer.fs b/src/Fabulous.MauiControls/Views/GestureRecognizers/DragGestureRecognizer.fs index 4b4a030..40d80b4 100644 --- a/src/Fabulous.MauiControls/Views/GestureRecognizers/DragGestureRecognizer.fs +++ b/src/Fabulous.MauiControls/Views/GestureRecognizers/DragGestureRecognizer.fs @@ -12,11 +12,17 @@ module DragGestureRecognizer = let CanDrag = Attributes.defineBindableBool DragGestureRecognizer.CanDragProperty - let DragStarting = - Attributes.defineEvent "DragGestureRecognizer_DragStarting" (fun target -> (target :?> DragGestureRecognizer).DragStarting) + let DragStartingMsg = + Attributes.defineEvent "DragGestureRecognizer_DragStartingMsg" (fun target -> (target :?> DragGestureRecognizer).DragStarting) - let DropCompleted = - Attributes.defineEvent "DragGestureRecognizer_DropCompleted" (fun target -> (target :?> DragGestureRecognizer).DropCompleted) + let DragStartingFn = + Attributes.defineEventNoDispatch "DragGestureRecognizer_DragStartingFn" (fun target -> (target :?> DragGestureRecognizer).DragStarting) + + let DropCompletedMsg = + Attributes.defineEvent "DragGestureRecognizer_DropCompletedMsg" (fun target -> (target :?> DragGestureRecognizer).DropCompleted) + + let DropCompletedFn = + Attributes.defineEvent "DragGestureRecognizer_DropCompletedFn" (fun target -> (target :?> DragGestureRecognizer).DropCompleted) [] module DragGestureRecognizerBuilders = @@ -24,10 +30,18 @@ module DragGestureRecognizerBuilders = /// Create a DragGestureRecognizer that listens for DragStarting event /// Message to dispatch - static member inline DragGestureRecognizer<'msg>(onDragStarting: DragStartingEventArgs -> 'msg) = + static member inline DragGestureRecognizer<'msg when 'msg : equality>(onDragStarting: DragStartingEventArgs -> 'msg) = + WidgetBuilder<'msg, IFabDragGestureRecognizer>( + DragGestureRecognizer.WidgetKey, + DragGestureRecognizer.DragStartingMsg.WithValue(fun args -> onDragStarting args |> box) + ) + + /// Create a DragGestureRecognizer that listens for DragStarting event + /// Message to dispatch + static member inline DragGestureRecognizer(onDragStarting: DragStartingEventArgs -> unit) = WidgetBuilder<'msg, IFabDragGestureRecognizer>( DragGestureRecognizer.WidgetKey, - DragGestureRecognizer.DragStarting.WithValue(fun args -> onDragStarting args |> box) + DragGestureRecognizer.DragStartingMsg.WithValue(onDragStarting) ) [] @@ -43,8 +57,15 @@ type DragGestureRecognizerModifiers = /// Current widget /// Message to dispatch [] - static member inline onDropCompleted(this: WidgetBuilder<'msg, #IFabDragGestureRecognizer>, msg: 'msg) = - this.AddScalar(DragGestureRecognizer.DropCompleted.WithValue(fun _ -> box msg)) + static member inline onDropCompleted<'msg, 'marker when 'msg : equality and 'marker :> IFabDragGestureRecognizer>(this: WidgetBuilder<'msg, 'marker>, msg: 'msg) = + this.AddScalar(DragGestureRecognizer.DropCompletedMsg.WithValue(fun _ -> box msg)) + + /// Listen for DropCompleted event + /// Current widget + /// Function to execute + [] + static member inline onDropCompleted(this: WidgetBuilder<'msg, #IFabDragGestureRecognizer>, fn: unit -> unit) = + this.AddScalar(DragGestureRecognizer.DropCompletedFn.WithValue(fun _ -> fn())) /// Link a ViewRef to access the direct DragGestureRecognizer control instance /// Current widget diff --git a/src/Fabulous.MauiControls/Views/GestureRecognizers/DropGestureRecognizer.fs b/src/Fabulous.MauiControls/Views/GestureRecognizers/DropGestureRecognizer.fs index 14b04d3..47ba3cc 100644 --- a/src/Fabulous.MauiControls/Views/GestureRecognizers/DropGestureRecognizer.fs +++ b/src/Fabulous.MauiControls/Views/GestureRecognizers/DropGestureRecognizer.fs @@ -13,14 +13,23 @@ module DropGestureRecognizer = let AllowDrop = Attributes.defineBindableBool DropGestureRecognizer.AllowDropProperty - let Drop = - Attributes.defineEvent "DropGestureRecognizer_Drop" (fun target -> (target :?> DropGestureRecognizer).Drop) + let DropMsg = + Attributes.defineEvent "DropGestureRecognizer_DropMsg" (fun target -> (target :?> DropGestureRecognizer).Drop) - let DragOver = - Attributes.defineEvent "DropGestureRecognizer_DragOver" (fun target -> (target :?> DropGestureRecognizer).DragOver) + let DropFn = + Attributes.defineEventNoDispatch "DropGestureRecognizer_DropFn" (fun target -> (target :?> DropGestureRecognizer).Drop) - let DragLeave = - Attributes.defineEvent "DropGestureRecognizer_DragLeave" (fun target -> (target :?> DropGestureRecognizer).DragLeave) + let DragOverMsg = + Attributes.defineEvent "DropGestureRecognizer_DragOverMsg" (fun target -> (target :?> DropGestureRecognizer).DragOver) + + let DragOverFn = + Attributes.defineEvent "DropGestureRecognizer_DragOverFn" (fun target -> (target :?> DropGestureRecognizer).DragOver) + + let DragLeaveMsg = + Attributes.defineEvent "DropGestureRecognizer_DragLeaveMsg" (fun target -> (target :?> DropGestureRecognizer).DragLeave) + + let DragLeaveFn = + Attributes.defineEvent "DropGestureRecognizer_DragLeaveFn" (fun target -> (target :?> DropGestureRecognizer).DragLeave) [] module DropGestureRecognizerBuilders = @@ -28,10 +37,18 @@ module DropGestureRecognizerBuilders = /// Create a DropGestureRecognizer that listens for Drop event /// Message to dispatch - static member inline DropGestureRecognizer<'msg>(onDrop: DropEventArgs -> 'msg) = + static member inline DropGestureRecognizer<'msg when 'msg : equality>(onDrop: DropEventArgs -> 'msg) = + WidgetBuilder<'msg, IFabDropGestureRecognizer>( + DropGestureRecognizer.WidgetKey, + DropGestureRecognizer.DropMsg.WithValue(fun args -> onDrop args |> box) + ) + + /// Create a DropGestureRecognizer that listens for Drop event + /// Message to dispatch + static member inline DropGestureRecognizer(onDrop: DropEventArgs -> unit) = WidgetBuilder<'msg, IFabDropGestureRecognizer>( DropGestureRecognizer.WidgetKey, - DropGestureRecognizer.Drop.WithValue(fun args -> onDrop args |> box) + DropGestureRecognizer.DropFn.WithValue(onDrop) ) [] @@ -47,15 +64,29 @@ type DropGestureRecognizerModifiers = /// Current widget /// Message to dispatch [] - static member inline onDragOver(this: WidgetBuilder<'msg, #IFabDropGestureRecognizer>, fn: DragEventArgs -> 'msg) = - this.AddScalar(DropGestureRecognizer.DragOver.WithValue(fun args -> fn args |> box)) + static member inline onDragOver<'msg, 'marker when 'msg : equality and 'marker :> IFabDropGestureRecognizer>(this: WidgetBuilder<'msg, 'marker>, fn: DragEventArgs -> 'msg) = + this.AddScalar(DropGestureRecognizer.DragOverMsg.WithValue(fun args -> fn args |> box)) + + /// Listen for the DragOver event + /// Current widget + /// Message to dispatch + [] + static member inline onDragOver(this: WidgetBuilder<'msg, #IFabDropGestureRecognizer>, fn: DragEventArgs -> unit) = + this.AddScalar(DropGestureRecognizer.DragOverFn.WithValue(fn)) + + /// Listen for the DragLeave event + /// Current widget + /// Message to dispatch + [] + static member inline onDragLeave<'msg, 'marker when 'msg : equality and 'marker :> IFabDragGestureRecognizer>(this: WidgetBuilder<'msg, 'marker>, fn: DragEventArgs -> 'msg) = + this.AddScalar(DropGestureRecognizer.DragLeaveMsg.WithValue(fun args -> fn args |> box)) /// Listen for the DragLeave event /// Current widget /// Message to dispatch [] - static member inline onDragLeave(this: WidgetBuilder<'msg, #IFabDropGestureRecognizer>, fn: DragEventArgs -> 'msg) = - this.AddScalar(DropGestureRecognizer.DragLeave.WithValue(fun args -> fn args |> box)) + static member inline onDragLeave(this: WidgetBuilder<'msg, #IFabDropGestureRecognizer>, fn: DragEventArgs -> unit) = + this.AddScalar(DropGestureRecognizer.DragLeaveFn.WithValue(fn)) /// Link a ViewRef to access the direct DropGestureRecognizer control instance /// Current widget diff --git a/src/Fabulous.MauiControls/Views/GestureRecognizers/PanGestureRecognizer.fs b/src/Fabulous.MauiControls/Views/GestureRecognizers/PanGestureRecognizer.fs index 49dafd3..87eaef9 100644 --- a/src/Fabulous.MauiControls/Views/GestureRecognizers/PanGestureRecognizer.fs +++ b/src/Fabulous.MauiControls/Views/GestureRecognizers/PanGestureRecognizer.fs @@ -10,8 +10,11 @@ type IFabPanGestureRecognizer = module PanGestureRecognizer = let WidgetKey = Widgets.register() - let PanUpdated = - Attributes.defineEvent "PanGestureRecognizer_PanUpdated" (fun target -> (target :?> PanGestureRecognizer).PanUpdated) + let PanUpdatedMsg = + Attributes.defineEvent "PanGestureRecognizer_PanUpdatedMsg" (fun target -> (target :?> PanGestureRecognizer).PanUpdated) + + let PanUpdatedFn = + Attributes.defineEventNoDispatch "PanGestureRecognizer_PanUpdatedFn" (fun target -> (target :?> PanGestureRecognizer).PanUpdated) let TouchPoints = Attributes.defineBindableInt PanGestureRecognizer.TouchPointsProperty @@ -22,10 +25,18 @@ module PanGestureRecognizerBuilders = /// Create a PanGestureRecognizer that listens for Pan event /// Message to dispatch - static member inline PanGestureRecognizer<'msg>(onPanUpdated: PanUpdatedEventArgs -> 'msg) = + static member inline PanGestureRecognizer<'msg when 'msg : equality>(onPanUpdated: PanUpdatedEventArgs -> 'msg) = + WidgetBuilder<'msg, IFabPanGestureRecognizer>( + PanGestureRecognizer.WidgetKey, + PanGestureRecognizer.PanUpdatedMsg.WithValue(fun args -> onPanUpdated args |> box) + ) + + /// Create a PanGestureRecognizer that listens for Pan event + /// Message to dispatch + static member inline PanGestureRecognizer(onPanUpdated: PanUpdatedEventArgs -> unit) = WidgetBuilder<'msg, IFabPanGestureRecognizer>( PanGestureRecognizer.WidgetKey, - PanGestureRecognizer.PanUpdated.WithValue(fun args -> onPanUpdated args |> box) + PanGestureRecognizer.PanUpdatedFn.WithValue(onPanUpdated) ) [] diff --git a/src/Fabulous.MauiControls/Views/GestureRecognizers/PinchGestureRecognizer.fs b/src/Fabulous.MauiControls/Views/GestureRecognizers/PinchGestureRecognizer.fs index 9709bc4..9e9e187 100644 --- a/src/Fabulous.MauiControls/Views/GestureRecognizers/PinchGestureRecognizer.fs +++ b/src/Fabulous.MauiControls/Views/GestureRecognizers/PinchGestureRecognizer.fs @@ -10,8 +10,12 @@ type IFabPinchGestureRecognizer = module PinchGestureRecognizer = let WidgetKey = Widgets.register() - let PinchUpdated = - Attributes.defineEvent "PinchGestureRecognizer_PinchUpdated" (fun target -> + let PinchUpdatedMsg = + Attributes.defineEvent "PinchGestureRecognizer_PinchUpdatedMsg" (fun target -> + (target :?> PinchGestureRecognizer).PinchUpdated) + + let PinchUpdatedFn = + Attributes.defineEventNoDispatch "PinchGestureRecognizer_PinchUpdatedFn" (fun target -> (target :?> PinchGestureRecognizer).PinchUpdated) [] @@ -20,10 +24,18 @@ module PinchGestureRecognizerBuilders = /// Create a PinchGestureRecognizer that listens for Pinch event /// Message to dispatch - static member inline PinchGestureRecognizer<'msg>(onPinchUpdated: PinchGestureUpdatedEventArgs -> 'msg) = + static member inline PinchGestureRecognizer<'msg when 'msg : equality>(onPinchUpdated: PinchGestureUpdatedEventArgs -> 'msg) = + WidgetBuilder<'msg, IFabPinchGestureRecognizer>( + PinchGestureRecognizer.WidgetKey, + PinchGestureRecognizer.PinchUpdatedMsg.WithValue(fun args -> onPinchUpdated args |> box) + ) + + /// Create a PinchGestureRecognizer that listens for Pinch event + /// Message to dispatch + static member inline PinchGestureRecognizer(onPinchUpdated: PinchGestureUpdatedEventArgs -> unit) = WidgetBuilder<'msg, IFabPinchGestureRecognizer>( PinchGestureRecognizer.WidgetKey, - PinchGestureRecognizer.PinchUpdated.WithValue(fun args -> onPinchUpdated args |> box) + PinchGestureRecognizer.PinchUpdatedFn.WithValue(onPinchUpdated) ) [] diff --git a/src/Fabulous.MauiControls/Views/GestureRecognizers/SwipeGestureRecognizer.fs b/src/Fabulous.MauiControls/Views/GestureRecognizers/SwipeGestureRecognizer.fs index 2b8f366..cfec69f 100644 --- a/src/Fabulous.MauiControls/Views/GestureRecognizers/SwipeGestureRecognizer.fs +++ b/src/Fabulous.MauiControls/Views/GestureRecognizers/SwipeGestureRecognizer.fs @@ -14,8 +14,11 @@ module SwipeGestureRecognizer = let Direction = Attributes.defineBindableEnum SwipeGestureRecognizer.DirectionProperty - let Swiped = - Attributes.defineEvent "SwipeGestureRecognizer_Swiped" (fun target -> (target :?> SwipeGestureRecognizer).Swiped) + let SwipedMsg = + Attributes.defineEvent "SwipeGestureRecognizer_SwipedMsg" (fun target -> (target :?> SwipeGestureRecognizer).Swiped) + + let SwipedFn = + Attributes.defineEventNoDispatch "SwipeGestureRecognizer_SwipedFn" (fun target -> (target :?> SwipeGestureRecognizer).Swiped) let Threshold = Attributes.defineBindableInt SwipeGestureRecognizer.ThresholdProperty @@ -26,10 +29,18 @@ module SwipeGestureRecognizerBuilders = /// Create a SwipeGestureRecognizer that listens for Swipe event /// Message to dispatch - static member inline SwipeGestureRecognizer<'msg>(onSwiped: SwipeDirection -> 'msg) = + static member inline SwipeGestureRecognizer<'msg when 'msg : equality>(onSwiped: SwipeDirection -> 'msg) = + WidgetBuilder<'msg, IFabSwipeGestureRecognizer>( + SwipeGestureRecognizer.WidgetKey, + SwipeGestureRecognizer.SwipedMsg.WithValue(fun args -> onSwiped args.Direction |> box) + ) + + /// Create a SwipeGestureRecognizer that listens for Swipe event + /// Message to dispatch + static member inline SwipeGestureRecognizer(onSwiped: SwipeDirection -> unit) = WidgetBuilder<'msg, IFabSwipeGestureRecognizer>( SwipeGestureRecognizer.WidgetKey, - SwipeGestureRecognizer.Swiped.WithValue(fun args -> onSwiped args.Direction |> box) + SwipeGestureRecognizer.SwipedFn.WithValue(fun args -> onSwiped args.Direction) ) [] diff --git a/src/Fabulous.MauiControls/Views/GestureRecognizers/TapGestureRecognizer.fs b/src/Fabulous.MauiControls/Views/GestureRecognizers/TapGestureRecognizer.fs index 1224334..b736d0c 100644 --- a/src/Fabulous.MauiControls/Views/GestureRecognizers/TapGestureRecognizer.fs +++ b/src/Fabulous.MauiControls/Views/GestureRecognizers/TapGestureRecognizer.fs @@ -13,8 +13,11 @@ module TapGestureRecognizer = let NumberOfTapsRequired = Attributes.defineBindableInt TapGestureRecognizer.NumberOfTapsRequiredProperty - let Tapped = - Attributes.defineEvent "TapGestureRecognizer_Tapped" (fun target -> (target :?> TapGestureRecognizer).Tapped) + let TappedMsg = + Attributes.defineEvent "TapGestureRecognizer_TappedMsg" (fun target -> (target :?> TapGestureRecognizer).Tapped) + + let TappedFn = + Attributes.defineEventNoDispatch "TapGestureRecognizer_TappedFn" (fun target -> (target :?> TapGestureRecognizer).Tapped) [] module TapGestureRecognizerBuilders = @@ -22,8 +25,13 @@ module TapGestureRecognizerBuilders = /// Create a TapGestureRecognizer that listens for Tapped event /// Message to dispatch - static member inline TapGestureRecognizer<'msg>(onTapped: 'msg) = - WidgetBuilder<'msg, IFabTapGestureRecognizer>(TapGestureRecognizer.WidgetKey, TapGestureRecognizer.Tapped.WithValue(fun _ -> box onTapped)) + static member inline TapGestureRecognizer<'msg when 'msg : equality>(onTapped: 'msg) = + WidgetBuilder<'msg, IFabTapGestureRecognizer>(TapGestureRecognizer.WidgetKey, TapGestureRecognizer.TappedMsg.WithValue(fun _ -> box onTapped)) + + /// Create a TapGestureRecognizer that listens for Tapped event + /// Message to dispatch + static member inline TapGestureRecognizer(onTapped: unit -> unit) = + WidgetBuilder<'msg, IFabTapGestureRecognizer>(TapGestureRecognizer.WidgetKey, TapGestureRecognizer.TappedFn.WithValue(fun _ -> onTapped())) [] type TapGestureRecognizerModifiers = diff --git a/src/Fabulous.MauiControls/Views/KeyboardAccelerator.fs b/src/Fabulous.MauiControls/Views/KeyboardAccelerator.fs index 334d674..502e625 100644 --- a/src/Fabulous.MauiControls/Views/KeyboardAccelerator.fs +++ b/src/Fabulous.MauiControls/Views/KeyboardAccelerator.fs @@ -23,13 +23,13 @@ module KeyboardAcceleratorBuilders = /// Create a KeyboardAccelerator widget with a key /// The key triggering the accelerator - static member inline KeyboardAccelerator<'msg>(key: string) = + static member inline KeyboardAccelerator(key: string) = WidgetBuilder<'msg, IFabKeyboardAccelerator>(KeyboardAccelerator.WidgetKey, KeyboardAccelerator.Key.WithValue(key)) /// Create a KeyboardAccelerator widget with a key and a modifier /// The key triggering the accelerator /// The modifiers required to trigger the accelerator - static member inline KeyboardAccelerator<'msg>(key: string, modifiers: KeyboardAcceleratorModifiers) = + static member inline KeyboardAccelerator(key: string, modifiers: KeyboardAcceleratorModifiers) = WidgetBuilder<'msg, IFabKeyboardAccelerator>( KeyboardAccelerator.WidgetKey, KeyboardAccelerator.Key.WithValue(key), diff --git a/src/Fabulous.MauiControls/Views/Layouts/AbsoluteLayout.fs b/src/Fabulous.MauiControls/Views/Layouts/AbsoluteLayout.fs index 1eb4b8d..03e2a10 100644 --- a/src/Fabulous.MauiControls/Views/Layouts/AbsoluteLayout.fs +++ b/src/Fabulous.MauiControls/Views/Layouts/AbsoluteLayout.fs @@ -23,7 +23,7 @@ module AbsoluteLayoutBuilders = type Fabulous.Maui.View with /// Create an AbsoluteLayout widget - static member inline AbsoluteLayout<'msg>() = + static member inline AbsoluteLayout() = CollectionBuilder<'msg, IFabAbsoluteLayout, IFabView>(AbsoluteLayout.WidgetKey, LayoutOfView.Children) [] diff --git a/src/Fabulous.MauiControls/Views/Layouts/ContentView.fs b/src/Fabulous.MauiControls/Views/Layouts/ContentView.fs index da4bfd4..d60bedc 100644 --- a/src/Fabulous.MauiControls/Views/Layouts/ContentView.fs +++ b/src/Fabulous.MauiControls/Views/Layouts/ContentView.fs @@ -18,7 +18,7 @@ module ContentViewBuilders = /// Create a ContentView widget with a content /// The content widget - static member inline ContentView<'msg, 'marker when 'marker :> IFabView>(content: WidgetBuilder<'msg, 'marker>) = + static member inline ContentView(content: WidgetBuilder<'msg, #IFabView>) = WidgetHelpers.buildWidgets<'msg, IFabContentView> ContentView.WidgetKey [| ContentView.Content.WithValue(content.Compile()) |] [] diff --git a/src/Fabulous.MauiControls/Views/Layouts/FlexLayout.fs b/src/Fabulous.MauiControls/Views/Layouts/FlexLayout.fs index bbb0015..4788b41 100644 --- a/src/Fabulous.MauiControls/Views/Layouts/FlexLayout.fs +++ b/src/Fabulous.MauiControls/Views/Layouts/FlexLayout.fs @@ -49,12 +49,12 @@ module FlexLayoutBuilders = type Fabulous.Maui.View with /// Create a FlexLayout - static member inline FlexLayout<'msg>() = + static member inline FlexLayout() = CollectionBuilder<'msg, IFabFlexLayout, IFabView>(FlexLayout.WidgetKey, LayoutOfView.Children) /// Create a FlexLayout widget with a wrap value /// The wrap value - static member inline FlexLayout<'msg>(wrap: FlexWrap) = + static member inline FlexLayout(wrap: FlexWrap) = CollectionBuilder<'msg, IFabFlexLayout, IFabView>(FlexLayout.WidgetKey, LayoutOfView.Children, FlexLayout.Wrap.WithValue(wrap)) [] diff --git a/src/Fabulous.MauiControls/Views/Layouts/Grid.fs b/src/Fabulous.MauiControls/Views/Layouts/Grid.fs index 213a3d0..557a855 100644 --- a/src/Fabulous.MauiControls/Views/Layouts/Grid.fs +++ b/src/Fabulous.MauiControls/Views/Layouts/Grid.fs @@ -83,13 +83,13 @@ module GridBuilders = type Fabulous.Maui.View with /// Create a Grid widget with only one cell - static member inline Grid<'msg>() = + static member inline Grid() = CollectionBuilder<'msg, IFabGrid, IFabView>(Grid.WidgetKey, LayoutOfView.Children) /// Create a Grid widget with the given column and row definitions /// The column definitions /// The row definitions - static member inline Grid<'msg>(coldefs: seq, rowdefs: seq) = + static member inline Grid(coldefs: seq, rowdefs: seq) = CollectionBuilder<'msg, IFabGrid, IFabView>( Grid.WidgetKey, LayoutOfView.Children, diff --git a/src/Fabulous.MauiControls/Views/Layouts/HorizontalStackLayout.fs b/src/Fabulous.MauiControls/Views/Layouts/HorizontalStackLayout.fs index 39c0aca..f2fa891 100644 --- a/src/Fabulous.MauiControls/Views/Layouts/HorizontalStackLayout.fs +++ b/src/Fabulous.MauiControls/Views/Layouts/HorizontalStackLayout.fs @@ -15,12 +15,12 @@ module HorizontalStackLayoutBuilders = type Fabulous.Maui.View with /// Creates a HStack widget - static member inline HStack<'msg>() = + static member inline HStack() = CollectionBuilder<'msg, IFabHorizontalStackLayout, IFabView>(HorizontalStackLayout.WidgetKey, LayoutOfView.Children) /// Creates a HStack widget with spacing between children /// The spacing between children - static member inline HStack<'msg>(spacing: float) = + static member inline HStack(spacing: float) = CollectionBuilder<'msg, IFabHorizontalStackLayout, IFabView>( HorizontalStackLayout.WidgetKey, LayoutOfView.Children, diff --git a/src/Fabulous.MauiControls/Views/Layouts/RefreshView.fs b/src/Fabulous.MauiControls/Views/Layouts/RefreshView.fs index dcd1f55..57d1cd8 100644 --- a/src/Fabulous.MauiControls/Views/Layouts/RefreshView.fs +++ b/src/Fabulous.MauiControls/Views/Layouts/RefreshView.fs @@ -16,8 +16,11 @@ module RefreshView = let RefreshColor = Attributes.defineBindableColor RefreshView.RefreshColorProperty - let Refreshing = - Attributes.defineEventNoArg "RefreshView_Refreshing" (fun target -> (target :?> RefreshView).Refreshing) + let RefreshingMsg = + Attributes.defineEventNoArg "RefreshView_RefreshingMsg" (fun target -> (target :?> RefreshView).Refreshing) + + let RefreshingFn = + Attributes.defineEventNoArgNoDispatch "RefreshView_RefreshingFn" (fun target -> (target :?> RefreshView).Refreshing) [] module RefreshViewBuilders = @@ -31,7 +34,21 @@ module RefreshViewBuilders = WidgetBuilder<'msg, IFabRefreshView>( RefreshView.WidgetKey, AttributesBundle( - StackList.two(RefreshView.IsRefreshing.WithValue(isRefreshing), RefreshView.Refreshing.WithValue(MsgValue(onRefreshing))), + StackList.two(RefreshView.IsRefreshing.WithValue(isRefreshing), RefreshView.RefreshingMsg.WithValue(MsgValue(onRefreshing))), + ValueSome [| ContentView.Content.WithValue(content.Compile()) |], + ValueNone + ) + ) + + /// Create a RefreshView widget with content + /// The refresh state + /// Message to dispatch when refresh state changes + /// The content widget + static member inline RefreshView(isRefreshing: bool, onRefreshing: unit -> unit, content: WidgetBuilder<'msg, #IFabView>) = + WidgetBuilder<'msg, IFabRefreshView>( + RefreshView.WidgetKey, + AttributesBundle( + StackList.two(RefreshView.IsRefreshing.WithValue(isRefreshing), RefreshView.RefreshingFn.WithValue(onRefreshing)), ValueSome [| ContentView.Content.WithValue(content.Compile()) |], ValueNone ) diff --git a/src/Fabulous.MauiControls/Views/Layouts/ScrollView.fs b/src/Fabulous.MauiControls/Views/Layouts/ScrollView.fs index 2c6441d..2d5e533 100644 --- a/src/Fabulous.MauiControls/Views/Layouts/ScrollView.fs +++ b/src/Fabulous.MauiControls/Views/Layouts/ScrollView.fs @@ -26,8 +26,11 @@ module ScrollView = let Orientation = Attributes.defineBindableEnum ScrollView.OrientationProperty - let Scrolled = - Attributes.defineEvent "ScrollView_Scrolled" (fun target -> (target :?> ScrollView).Scrolled) + let ScrolledMsg = + Attributes.defineEvent "ScrollView_ScrolledMsg" (fun target -> (target :?> ScrollView).Scrolled) + + let ScrolledFn = + Attributes.defineEventNoDispatch "ScrollView_ScrolledFn" (fun target -> (target :?> ScrollView).Scrolled) let ScrollPosition = Attributes.defineSimpleScalarWithEquality "ScrollView_ScrollPosition" (fun _ newValueOpt node -> @@ -55,7 +58,7 @@ module ScrollViewBuilders = /// Create a ScrollView widget with a content /// The content of the ScrollView - static member inline ScrollView<'msg, 'marker when 'marker :> IFabView>(content: WidgetBuilder<'msg, 'marker>) = + static member inline ScrollView(content: WidgetBuilder<'msg, #IFabView>) = WidgetHelpers.buildWidgets<'msg, IFabScrollView> ScrollView.WidgetKey [| ScrollView.Content.WithValue(content.Compile()) |] [] @@ -94,7 +97,14 @@ type ScrollViewModifiers = /// Message to dispatch [] static member inline onScrolled(this: WidgetBuilder<'msg, #IFabScrollView>, fn: ScrolledEventArgs -> 'msg) = - this.AddScalar(ScrollView.Scrolled.WithValue(fun args -> fn args |> box)) + this.AddScalar(ScrollView.ScrolledMsg.WithValue(fun args -> fn args |> box)) + + /// Listen for the Scrolled event + /// Current widget + /// Message to dispatch + [] + static member inline onScrolled(this: WidgetBuilder<'msg, #IFabScrollView>, fn: ScrolledEventArgs -> unit) = + this.AddScalar(ScrollView.ScrolledFn.WithValue(fn)) /// Link a ViewRef to access the direct ScrollView control instance /// Current widget diff --git a/src/Fabulous.MauiControls/Views/Layouts/SwipeItem.fs b/src/Fabulous.MauiControls/Views/Layouts/SwipeItem.fs index 72ef671..ea5f67e 100644 --- a/src/Fabulous.MauiControls/Views/Layouts/SwipeItem.fs +++ b/src/Fabulous.MauiControls/Views/Layouts/SwipeItem.fs @@ -14,8 +14,11 @@ module SwipeItem = let BackgroundColor = Attributes.defineBindableColor SwipeItem.BackgroundColorProperty - let Invoked = - Attributes.defineEvent "SwipeItem_Invoked" (fun target -> (target :?> SwipeItem).Invoked) + let InvokedMsg = + Attributes.defineEvent "SwipeItem_InvokedMsg" (fun target -> (target :?> SwipeItem).Invoked) + + let InvokedFn = + Attributes.defineEvent "SwipeItem_InvokedFn" (fun target -> (target :?> SwipeItem).Invoked) let IsVisible = Attributes.defineBindableBool SwipeItem.IsVisibleProperty @@ -25,8 +28,13 @@ module SwipeItemBuilders = /// Create a SwipeItem widget and listen for the Invoke event /// Message to dispatch - static member inline SwipeItem<'msg>(onInvoked: 'msg) = - WidgetBuilder<'msg, IFabSwipeItem>(SwipeItem.WidgetKey, SwipeItem.Invoked.WithValue(fun _ -> box onInvoked)) + static member inline SwipeItem(onInvoked: 'msg) = + WidgetBuilder<'msg, IFabSwipeItem>(SwipeItem.WidgetKey, SwipeItem.InvokedMsg.WithValue(fun _ -> box onInvoked)) + + /// Create a SwipeItem widget and listen for the Invoke event + /// Message to dispatch + static member inline SwipeItem(onInvoked: unit -> unit) = + WidgetBuilder<'msg, IFabSwipeItem>(SwipeItem.WidgetKey, SwipeItem.InvokedFn.WithValue(fun _ -> onInvoked())) [] type SwipeItemModifiers() = diff --git a/src/Fabulous.MauiControls/Views/Layouts/SwipeItems.fs b/src/Fabulous.MauiControls/Views/Layouts/SwipeItems.fs index aad3440..a6f5f4d 100644 --- a/src/Fabulous.MauiControls/Views/Layouts/SwipeItems.fs +++ b/src/Fabulous.MauiControls/Views/Layouts/SwipeItems.fs @@ -27,7 +27,7 @@ module SwipeItemsBuilders = type Fabulous.Maui.View with /// Create a SwipeItems widget - static member inline SwipeItems<'msg>() = + static member inline SwipeItems() = CollectionBuilder<'msg, IFabSwipeItems, IFabSwipeItem>(SwipeItems.WidgetKey, SwipeItems.SwipeItems) [] diff --git a/src/Fabulous.MauiControls/Views/Layouts/SwipeView.fs b/src/Fabulous.MauiControls/Views/Layouts/SwipeView.fs index 5607964..abe859a 100644 --- a/src/Fabulous.MauiControls/Views/Layouts/SwipeView.fs +++ b/src/Fabulous.MauiControls/Views/Layouts/SwipeView.fs @@ -12,24 +12,39 @@ module SwipeView = let BottomSwipeItems = Attributes.defineBindableWidget SwipeView.BottomItemsProperty - let CloseRequested = - Attributes.defineEvent "SwipeView_CloseRequested" (fun target -> (target :?> SwipeView).CloseRequested) + let CloseRequestedMsg = + Attributes.defineEvent "SwipeView_CloseRequestedMsg" (fun target -> (target :?> SwipeView).CloseRequested) + + let CloseRequestedFn = + Attributes.defineEventNoDispatch "SwipeView_CloseRequestedFn" (fun target -> (target :?> SwipeView).CloseRequested) let LeftSwipeItems = Attributes.defineBindableWidget SwipeView.LeftItemsProperty - let OpenRequested = - Attributes.defineEvent "SwipeView_OpenRequested" (fun target -> (target :?> SwipeView).OpenRequested) + let OpenRequestedMsg = + Attributes.defineEvent "SwipeView_OpenRequestedMsg" (fun target -> (target :?> SwipeView).OpenRequested) + + let OpenRequestedFn = + Attributes.defineEventNoDispatch "SwipeView_OpenRequestedFn" (fun target -> (target :?> SwipeView).OpenRequested) let RightSwipeItems = Attributes.defineBindableWidget SwipeView.RightItemsProperty - let SwipeChanging = - Attributes.defineEvent "SwipeView_SwipeChanging" (fun target -> (target :?> SwipeView).SwipeChanging) + let SwipeChangingMsg = + Attributes.defineEvent "SwipeView_SwipeChangingMsg" (fun target -> (target :?> SwipeView).SwipeChanging) + + let SwipeChangingFn = + Attributes.defineEventNoDispatch "SwipeView_SwipeChangingFn" (fun target -> (target :?> SwipeView).SwipeChanging) + + let SwipeEndedMsg = + Attributes.defineEvent "SwipeView_SwipeEndedMsg" (fun target -> (target :?> SwipeView).SwipeEnded) - let SwipeEnded = - Attributes.defineEvent "SwipeView_SwipeEnded" (fun target -> (target :?> SwipeView).SwipeEnded) + let SwipeEndedFn = + Attributes.defineEventNoDispatch "SwipeView_SwipeEndedFn" (fun target -> (target :?> SwipeView).SwipeEnded) - let SwipeStarted = - Attributes.defineEvent "SwipeView_SwipeStarted" (fun target -> (target :?> SwipeView).SwipeStarted) + let SwipeStartedMsg = + Attributes.defineEvent "SwipeView_SwipeStartedMsg" (fun target -> (target :?> SwipeView).SwipeStarted) + + let SwipeStartedFn = + Attributes.defineEventNoDispatch "SwipeView_SwipeStartedFn" (fun target -> (target :?> SwipeView).SwipeStarted) let SwipeThreshold = Attributes.defineBindableInt SwipeView.ThresholdProperty @@ -79,35 +94,70 @@ type SwipeViewModifiers() = /// Message to dispatch [] static member inline onSwipeStarted(this: WidgetBuilder<'msg, #IFabSwipeView>, fn: SwipeStartedEventArgs -> 'msg) = - this.AddScalar(SwipeView.SwipeStarted.WithValue(fun args -> fn args |> box)) + this.AddScalar(SwipeView.SwipeStartedMsg.WithValue(fun args -> fn args |> box)) + + /// Listen to the SwipeStarted event + /// Current widget + /// Message to dispatch + [] + static member inline onSwipeStarted(this: WidgetBuilder<'msg, #IFabSwipeView>, fn: SwipeStartedEventArgs -> unit) = + this.AddScalar(SwipeView.SwipeStartedFn.WithValue(fn)) /// Listen to the SwipeChanging event /// Current widget /// Message to dispatch [] static member inline onSwipeChanging(this: WidgetBuilder<'msg, #IFabSwipeView>, fn: SwipeChangingEventArgs -> 'msg) = - this.AddScalar(SwipeView.SwipeChanging.WithValue(fun args -> fn args |> box)) + this.AddScalar(SwipeView.SwipeChangingMsg.WithValue(fun args -> fn args |> box)) + + /// Listen to the SwipeChanging event + /// Current widget + /// Message to dispatch + [] + static member inline onSwipeChanging(this: WidgetBuilder<'msg, #IFabSwipeView>, fn: SwipeChangingEventArgs -> unit) = + this.AddScalar(SwipeView.SwipeChangingFn.WithValue(fn)) /// Listen to the SwipeEnded event /// Current widget /// Message to dispatch [] static member inline onSwipeEnded(this: WidgetBuilder<'msg, #IFabSwipeView>, fn: SwipeEndedEventArgs -> 'msg) = - this.AddScalar(SwipeView.SwipeEnded.WithValue(fun args -> fn args |> box)) + this.AddScalar(SwipeView.SwipeEndedMsg.WithValue(fun args -> fn args |> box)) + + /// Listen to the SwipeEnded event + /// Current widget + /// Message to dispatch + [] + static member inline onSwipeEnded(this: WidgetBuilder<'msg, #IFabSwipeView>, fn: SwipeEndedEventArgs -> unit) = + this.AddScalar(SwipeView.SwipeEndedFn.WithValue(fn)) /// Listen to the OpenRequested event /// Current widget /// Message to dispatch [] static member inline onOpenRequested(this: WidgetBuilder<'msg, #IFabSwipeView>, fn: OpenRequestedEventArgs -> 'msg) = - this.AddScalar(SwipeView.OpenRequested.WithValue(fun args -> fn args |> box)) + this.AddScalar(SwipeView.OpenRequestedMsg.WithValue(fun args -> fn args |> box)) + + /// Listen to the OpenRequested event + /// Current widget + /// Message to dispatch + [] + static member inline onOpenRequested(this: WidgetBuilder<'msg, #IFabSwipeView>, fn: OpenRequestedEventArgs -> unit) = + this.AddScalar(SwipeView.OpenRequestedFn.WithValue(fn)) /// Listen to the CloseRequested event /// Current widget /// Message to dispatch [] static member inline onCloseRequested(this: WidgetBuilder<'msg, #IFabSwipeView>, fn: CloseRequestedEventArgs -> 'msg) = - this.AddScalar(SwipeView.CloseRequested.WithValue(fun args -> fn args |> box)) + this.AddScalar(SwipeView.CloseRequestedMsg.WithValue(fun args -> fn args |> box)) + + /// Listen to the CloseRequested event + /// Current widget + /// Message to dispatch + [] + static member inline onCloseRequested(this: WidgetBuilder<'msg, #IFabSwipeView>, fn: CloseRequestedEventArgs -> unit) = + this.AddScalar(SwipeView.CloseRequestedFn.WithValue(fn)) /// Set the top swipe items /// Current widget diff --git a/src/Fabulous.MauiControls/Views/Layouts/VerticalStackLayout.fs b/src/Fabulous.MauiControls/Views/Layouts/VerticalStackLayout.fs index 1352fc3..09aba9a 100644 --- a/src/Fabulous.MauiControls/Views/Layouts/VerticalStackLayout.fs +++ b/src/Fabulous.MauiControls/Views/Layouts/VerticalStackLayout.fs @@ -15,12 +15,12 @@ module VerticalStackLayoutBuilders = type Fabulous.Maui.View with /// Creates a VStack widget - static member inline VStack<'msg>() = + static member inline VStack() = CollectionBuilder<'msg, IFabVerticalStackLayout, IFabView>(VerticalStackLayout.WidgetKey, LayoutOfView.Children) /// Creates a VStack widget with spacing between children /// The spacing between children - static member inline VStack<'msg>(spacing: float) = + static member inline VStack(spacing: float) = CollectionBuilder<'msg, IFabVerticalStackLayout, IFabView>( VerticalStackLayout.WidgetKey, LayoutOfView.Children, diff --git a/src/Fabulous.MauiControls/Views/Layouts/ZStack.fs b/src/Fabulous.MauiControls/Views/Layouts/ZStack.fs new file mode 100644 index 0000000..29c8414 --- /dev/null +++ b/src/Fabulous.MauiControls/Views/Layouts/ZStack.fs @@ -0,0 +1,27 @@ +namespace Fabulous.Maui + +open System.Runtime.CompilerServices +open Fabulous +open Microsoft.Maui.Controls + +type IFabZStack = + inherit IFabLayoutOfView + +module ZStack = + // Remark: ZStack control is not available in Maui, so we use a Grid control instead to simulate the ZStack behavior + let WidgetKey = Widgets.register() + +[] +module ZStackBuilders = + type Fabulous.Maui.View with + static member inline ZStack() = + CollectionBuilder<'msg, IFabZStack, IFabView>(ZStack.WidgetKey, LayoutOfView.Children) + +[] +type ZStackModifiers = + /// Link a ViewRef to access the direct Grid control instance + /// Current widget + /// The ViewRef instance that will receive access to the underlying control + [] + static member inline reference(this: WidgetBuilder<'msg, IFabZStack>, value: ViewRef) = + this.AddScalar(ViewRefAttributes.ViewRef.WithValue(value.Unbox)) \ No newline at end of file diff --git a/src/Fabulous.MauiControls/Views/MenuItems/MenuFlyoutItem.fs b/src/Fabulous.MauiControls/Views/MenuItems/MenuFlyoutItem.fs index fd21dfc..e306986 100644 --- a/src/Fabulous.MauiControls/Views/MenuItems/MenuFlyoutItem.fs +++ b/src/Fabulous.MauiControls/Views/MenuItems/MenuFlyoutItem.fs @@ -21,15 +21,21 @@ module MenuFlyoutItemBuilders = /// Create a MenuItem widget with a text and a Click callback /// The text /// The click callback - static member inline MenuFlyoutItem<'msg>(text: string, onClicked: 'msg) = - WidgetBuilder<'msg, IFabMenuFlyoutItem>(MenuItem.WidgetKey, MenuItem.Text.WithValue(text), MenuItem.Clicked.WithValue(MsgValue(onClicked))) + static member inline MenuFlyoutItem(text: string, onClicked: 'msg) = + WidgetBuilder<'msg, IFabMenuFlyoutItem>(MenuItem.WidgetKey, MenuItem.Text.WithValue(text), MenuItem.ClickedMsg.WithValue(MsgValue(onClicked))) + + /// Create a MenuItem widget with a text and a Click callback + /// The text + /// The click callback + static member inline MenuFlyoutItem(text: string, onClicked: unit -> unit) = + WidgetBuilder<'msg, IFabMenuFlyoutItem>(MenuItem.WidgetKey, MenuItem.Text.WithValue(text), MenuItem.ClickedFn.WithValue(onClicked)) [] type MenuFlyoutItemModifiers = /// Set the keyboard accelerators of this widget /// Current widget [] - static member inline keyboardAccelerators<'msg, 'marker when 'marker :> IFabMenuFlyoutItem>(this: WidgetBuilder<'msg, 'marker>) = + static member inline keyboardAccelerators<'msg, 'marker when 'msg : equality and 'marker :> IFabMenuFlyoutItem>(this: WidgetBuilder<'msg, 'marker>) = WidgetHelpers.buildAttributeCollection<'msg, 'marker, IFabKeyboardAccelerator> MenuFlyoutItem.KeyboardAccelerators this [] diff --git a/src/Fabulous.MauiControls/Views/MenuItems/MenuItem.fs b/src/Fabulous.MauiControls/Views/MenuItems/MenuItem.fs index db73648..9eda680 100644 --- a/src/Fabulous.MauiControls/Views/MenuItems/MenuItem.fs +++ b/src/Fabulous.MauiControls/Views/MenuItems/MenuItem.fs @@ -14,11 +14,11 @@ type IFabMenuItem = module MenuItem = let WidgetKey = Widgets.register() - [] - let Accelerator = Attributes.defineBindableWithEquality MenuItem.AcceleratorProperty + let ClickedMsg = + Attributes.defineEventNoArg "MenuItem_ClickedMsg" (fun target -> (target :?> MenuItem).Clicked) - let Clicked = - Attributes.defineEventNoArg "MenuItem_Clicked" (fun target -> (target :?> MenuItem).Clicked) + let ClickedFn = + Attributes.defineEventNoArgNoDispatch "MenuItem_ClickedFn" (fun target -> (target :?> MenuItem).Clicked) let IconImageSource = Attributes.defineBindableImageSource MenuItem.IconImageSourceProperty @@ -34,19 +34,17 @@ module MenuItemBuilders = /// Create a MenuItem widget with a text and a Click callback /// The text /// The click callback - static member inline MenuItem<'msg>(text: string, onClicked: 'msg) = - WidgetBuilder<'msg, IFabMenuItem>(MenuItem.WidgetKey, MenuItem.Text.WithValue(text), MenuItem.Clicked.WithValue(MsgValue(onClicked))) + static member inline MenuItem(text: string, onClicked: 'msg) = + WidgetBuilder<'msg, IFabMenuItem>(MenuItem.WidgetKey, MenuItem.Text.WithValue(text), MenuItem.ClickedMsg.WithValue(MsgValue(onClicked))) + + /// Create a MenuItem widget with a text and a Click callback + /// The text + /// The click callback + static member inline MenuItem(text: string, onClicked: unit -> unit) = + WidgetBuilder<'msg, IFabMenuItem>(MenuItem.WidgetKey, MenuItem.Text.WithValue(text), MenuItem.ClickedFn.WithValue(onClicked)) [] type MenuItemModifiers = - /// Set the accelerator of this widget - /// Current widget - /// The accelerator value - [] - [] - static member inline accelerator(this: WidgetBuilder<'msg, #IFabMenuItem>, value: Accelerator) = - this.AddScalar(MenuItem.Accelerator.WithValue(value)) - /// Set the source of the icon image /// Current widget /// The source of the icon image diff --git a/src/Fabulous.MauiControls/Views/MenuItems/ToolbarItem.fs b/src/Fabulous.MauiControls/Views/MenuItems/ToolbarItem.fs index 165e1f5..346ac8b 100644 --- a/src/Fabulous.MauiControls/Views/MenuItems/ToolbarItem.fs +++ b/src/Fabulous.MauiControls/Views/MenuItems/ToolbarItem.fs @@ -33,8 +33,14 @@ module ToolbarItemBuilders = /// Create a ToolbarItem widget with a text and a Click callback /// The text /// The click callback - static member inline ToolbarItem<'msg>(text: string, onClicked: 'msg) = - WidgetBuilder<'msg, IFabToolbarItem>(ToolbarItem.WidgetKey, MenuItem.Text.WithValue(text), MenuItem.Clicked.WithValue(MsgValue(onClicked))) + static member inline ToolbarItem(text: string, onClicked: 'msg) = + WidgetBuilder<'msg, IFabToolbarItem>(ToolbarItem.WidgetKey, MenuItem.Text.WithValue(text), MenuItem.ClickedMsg.WithValue(MsgValue(onClicked))) + + /// Create a ToolbarItem widget with a text and a Click callback + /// The text + /// The click callback + static member inline ToolbarItem(text: string, onClicked: unit -> unit) = + WidgetBuilder<'msg, IFabToolbarItem>(ToolbarItem.WidgetKey, MenuItem.Text.WithValue(text), MenuItem.ClickedFn.WithValue(onClicked)) [] type ToolbarItemModifiers = diff --git a/src/Fabulous.MauiControls/Views/Pages/ContentPage.fs b/src/Fabulous.MauiControls/Views/Pages/ContentPage.fs index 6ec9cf0..160180a 100644 --- a/src/Fabulous.MauiControls/Views/Pages/ContentPage.fs +++ b/src/Fabulous.MauiControls/Views/Pages/ContentPage.fs @@ -30,8 +30,11 @@ module ContentPage = let Content = Attributes.defineBindableWidget ContentPage.ContentProperty - let SizeAllocated = - Attributes.defineEvent "ContentPage_SizeAllocated" (fun target -> (target :?> FabContentPage).SizeAllocated) + let SizeAllocatedMsg = + Attributes.defineEvent "ContentPage_SizeAllocatedMsg" (fun target -> (target :?> FabContentPage).SizeAllocated) + + let SizeAllocatedFn = + Attributes.defineEventNoDispatch "ContentPage_SizeAllocatedFn" (fun target -> (target :?> FabContentPage).SizeAllocated) [] module ContentPageBuilders = @@ -39,13 +42,13 @@ module ContentPageBuilders = /// Create a ContentPage with a content widget /// The content widget - static member inline ContentPage<'msg, 'marker when 'marker :> IFabView>(content: WidgetBuilder<'msg, 'marker>) = + static member inline ContentPage<'msg, 'marker when 'msg : equality and 'marker :> IFabView>(content: WidgetBuilder<'msg, 'marker>) = WidgetBuilder<'msg, IFabContentPage>( ContentPage.WidgetKey, AttributesBundle(StackList.empty(), ValueSome [| ContentPage.Content.WithValue(content.Compile()) |], ValueNone) ) - static member inline ContentPage<'msg, 'childMarker>() = + static member inline ContentPage() = SingleChildBuilder<'msg, IFabContentPage, 'childMarker>(ContentPage.WidgetKey, ContentPage.Content) [] @@ -55,7 +58,14 @@ type ContentPageModifiers = /// Message to dispatch [] static member inline onSizeAllocated(this: WidgetBuilder<'msg, #IFabContentPage>, fn: SizeAllocatedEventArgs -> 'msg) = - this.AddScalar(ContentPage.SizeAllocated.WithValue(fn)) + this.AddScalar(ContentPage.SizeAllocatedMsg.WithValue(fn)) + + /// Listen for SizeAllocated event + /// Current widget + /// Message to dispatch + [] + static member inline onSizeAllocated(this: WidgetBuilder<'msg, #IFabContentPage>, fn: SizeAllocatedEventArgs -> unit) = + this.AddScalar(ContentPage.SizeAllocatedFn.WithValue(fn)) /// Link a ViewRef to access the direct ContentPage control instance /// Current widget diff --git a/src/Fabulous.MauiControls/Views/Pages/FlyoutPage.fs b/src/Fabulous.MauiControls/Views/Pages/FlyoutPage.fs index ecc88c5..e66a6c0 100644 --- a/src/Fabulous.MauiControls/Views/Pages/FlyoutPage.fs +++ b/src/Fabulous.MauiControls/Views/Pages/FlyoutPage.fs @@ -25,8 +25,11 @@ type FabFlyoutPage() as this = module FlyoutPage = let WidgetKey = Widgets.register() - let BackButtonPressed = - Attributes.defineEvent "FlyoutPage_BackButtonPressed" (fun target -> (target :?> FlyoutPage).BackButtonPressed) + let BackButtonPressedMsg = + Attributes.defineEvent "FlyoutPage_BackButtonPressedMsg" (fun target -> (target :?> FlyoutPage).BackButtonPressed) + + let BackButtonPressedFn = + Attributes.defineEventNoDispatch "FlyoutPage_BackButtonPressedFn" (fun target -> (target :?> FlyoutPage).BackButtonPressed) let Detail = Attributes.definePropertyWidget "FlyoutPage_Detail" (fun target -> (target :?> FlyoutPage).Detail :> obj) (fun target value -> @@ -42,8 +45,12 @@ module FlyoutPage = let IsGestureEnabled = Attributes.defineBindableBool FlyoutPage.IsGestureEnabledProperty - let IsPresented = - Attributes.defineBindableWithEvent "FlyoutPage_IsPresentedChanged" FlyoutPage.IsPresentedProperty (fun target -> + let IsPresentedMsg = + Attributes.defineBindableWithEvent "FlyoutPage_IsPresentedChangedMsg" FlyoutPage.IsPresentedProperty (fun target -> + (target :?> FabFlyoutPage).CustomIsPresentedChanged) + + let IsPresentedFn = + Attributes.defineBindableWithEventNoDispatch "FlyoutPage_IsPresentedChangedFn" FlyoutPage.IsPresentedProperty (fun target -> (target :?> FabFlyoutPage).CustomIsPresentedChanged) [] @@ -74,7 +81,15 @@ type FlyoutPageModifiers = /// Message to dispatch [] static member inline isPresented(this: WidgetBuilder<'msg, #IFabFlyoutPage>, value: bool, onChanged: bool -> 'msg) = - this.AddScalar(FlyoutPage.IsPresented.WithValue(ValueEventData.create value onChanged)) + this.AddScalar(FlyoutPage.IsPresentedMsg.WithValue(MsgValueEventData.create value onChanged)) + + /// Set whether the flyout is presented, and listen for presentation state changes + /// Current widget + /// The value indicating whether the flyout is presented + /// Message to dispatch + [] + static member inline isPresented(this: WidgetBuilder<'msg, #IFabFlyoutPage>, value: bool, onChanged: bool -> unit) = + this.AddScalar(FlyoutPage.IsPresentedFn.WithValue(ValueEventData.create value onChanged)) /// Set whether gesture is enabled to open the flyout /// Current widget @@ -88,7 +103,14 @@ type FlyoutPageModifiers = /// Message to dispatch [] static member inline onBackButtonPressed(this: WidgetBuilder<'msg, #IFabFlyoutPage>, fn: bool -> 'msg) = - this.AddScalar(FlyoutPage.BackButtonPressed.WithValue(fun args -> fn args.Handled)) + this.AddScalar(FlyoutPage.BackButtonPressedMsg.WithValue(fun args -> fn args.Handled)) + + /// Listen for back button pressed + /// Current widget + /// Message to dispatch + [] + static member inline onBackButtonPressed(this: WidgetBuilder<'msg, #IFabFlyoutPage>, fn: bool -> unit) = + this.AddScalar(FlyoutPage.BackButtonPressedFn.WithValue(fun args -> fn args.Handled)) /// Link a ViewRef to access the direct FlyoutPage control instance /// Current widget diff --git a/src/Fabulous.MauiControls/Views/Pages/NavigationPage.fs b/src/Fabulous.MauiControls/Views/Pages/NavigationPage.fs index b2d0039..73d9218 100644 --- a/src/Fabulous.MauiControls/Views/Pages/NavigationPage.fs +++ b/src/Fabulous.MauiControls/Views/Pages/NavigationPage.fs @@ -42,7 +42,7 @@ type RequiresSubscriptionEvent() = /// Maui handles pages asynchronously, meaning a page will be added to the stack only after the animation is finished. /// This is a problem for Fabulous, because the nav stack needs to be synchronized with the widget trees. -/// Otherwise rapid consecutive updates might end up with a wrong nav stack. +/// Otherwise, rapid consecutive updates might end up with a wrong nav stack. /// /// To work around that, we keep our own nav stack, and we update it synchronously. type FabNavigationPage() as this = @@ -268,11 +268,17 @@ module NavigationPageUpdaters = module NavigationPage = let WidgetKey = Widgets.register() - let BackButtonPressed = - Attributes.defineEventNoArg "NavigationPage_BackButtonPressed" (fun target -> (target :?> FabNavigationPage).BackButtonPressed) + let BackButtonPressedMsg = + Attributes.defineEventNoArg "NavigationPage_BackButtonPressedMsg" (fun target -> (target :?> FabNavigationPage).BackButtonPressed) - let BackNavigated = - Attributes.defineEventNoArg "NavigationPage_BackNavigated" (fun target -> (target :?> FabNavigationPage).BackNavigated) + let BackButtonPressedFn = + Attributes.defineEventNoArgNoDispatch "NavigationPage_BackButtonPressedFn" (fun target -> (target :?> FabNavigationPage).BackButtonPressed) + + let BackNavigatedMsg = + Attributes.defineEventNoArg "NavigationPage_BackNavigatedMsg" (fun target -> (target :?> FabNavigationPage).BackNavigated) + + let BackNavigatedFn = + Attributes.defineEventNoArgNoDispatch "NavigationPage_BackNavigatedFn" (fun target -> (target :?> FabNavigationPage).BackNavigated) let BarBackground = Attributes.defineBindableWithEquality NavigationPage.BarBackgroundProperty @@ -345,7 +351,7 @@ module NavigationPageBuilders = type Fabulous.Maui.View with /// Create a NavigationPage widget - static member inline NavigationPage<'msg>() = + static member inline NavigationPage() = CollectionBuilder<'msg, IFabNavigationPage, IFabPage>(NavigationPage.WidgetKey, NavigationPage.Pages) [] @@ -377,14 +383,29 @@ type NavigationPageModifiers = /// Setting this modifier will prevent the default behavior of the system back button. It's up to you to update the navigation stack. [] static member inline onBackButtonPressed(this: WidgetBuilder<'msg, #IFabNavigationPage>, msg: 'msg) = - this.AddScalar(NavigationPage.BackButtonPressed.WithValue(MsgValue(msg))) + this.AddScalar(NavigationPage.BackButtonPressedMsg.WithValue(MsgValue(msg))) + + /// Listen to the user pressing the system back button. Doesn't support the iOS back button + /// Current widget + /// Function to execute + /// Setting this modifier will prevent the default behavior of the system back button. It's up to you to update the navigation stack. + [] + static member inline onBackButtonPressed(this: WidgetBuilder<'msg, #IFabNavigationPage>, fn: unit -> unit) = + this.AddScalar(NavigationPage.BackButtonPressedFn.WithValue(fn)) /// Listen to the user back navigating /// Current widget /// Message to dispatch [] static member inline onBackNavigated(this: WidgetBuilder<'msg, #IFabNavigationPage>, msg: 'msg) = - this.AddScalar(NavigationPage.BackNavigated.WithValue(MsgValue(msg))) + this.AddScalar(NavigationPage.BackNavigatedMsg.WithValue(MsgValue(msg))) + + /// Listen to the user back navigating + /// Current widget + /// Function to execute + [] + static member inline onBackNavigated(this: WidgetBuilder<'msg, #IFabNavigationPage>, fn: unit -> unit) = + this.AddScalar(NavigationPage.BackNavigatedFn.WithValue(fn)) /// Link a ViewRef to access the direct NavigationPage control instance /// Current widget diff --git a/src/Fabulous.MauiControls/Views/Pages/TabbedPage.fs b/src/Fabulous.MauiControls/Views/Pages/TabbedPage.fs index ce22ec4..1035e50 100644 --- a/src/Fabulous.MauiControls/Views/Pages/TabbedPage.fs +++ b/src/Fabulous.MauiControls/Views/Pages/TabbedPage.fs @@ -40,7 +40,7 @@ module TabbedPageBuilders = type Fabulous.Maui.View with /// Create a TabbedPage widget - static member inline TabbedPage<'msg>() = + static member inline TabbedPage() = CollectionBuilder<'msg, IFabTabbedPage, IFabPage>(TabbedPage.WidgetKey, MultiPageOfPage.Children) [] diff --git a/src/Fabulous.MauiControls/Views/Pages/_MultiPageOfPage.fs b/src/Fabulous.MauiControls/Views/Pages/_MultiPageOfPage.fs index b66fe3f..5a04274 100644 --- a/src/Fabulous.MauiControls/Views/Pages/_MultiPageOfPage.fs +++ b/src/Fabulous.MauiControls/Views/Pages/_MultiPageOfPage.fs @@ -1,6 +1,5 @@ namespace Fabulous.Maui -open System open Fabulous open Fabulous.ScalarAttributeDefinitions open Microsoft.Maui.Controls @@ -13,17 +12,13 @@ module MultiPageOfPage = let Children = Attributes.defineListWidgetCollection "MultiPageOfPage" (fun target -> (target :?> MultiPage).Children) - [] - let CurrentPageChanged = - Attributes.defineEventNoArg "MultiPageOfPage_CurrentPageChanged" (fun target -> (target :?> MultiPage).CurrentPageChanged) - - let CurrentPageWithEvent = - let name = "MultiPageOfPage_CurrentPageWithEvent" + let CurrentPageWithEventMsg = + let name = "MultiPageOfPage_CurrentPageWithEventMsg" let key = SimpleScalarAttributeDefinition.CreateAttributeData( ScalarAttributeComparers.noCompare, - (fun oldValueOpt (newValueOpt: ValueEventData voption) node -> + (fun oldValueOpt (newValueOpt: MsgValueEventData voption) node -> let target = node.Target :?> MultiPage match newValueOpt with @@ -58,21 +53,64 @@ module MultiPageOfPage = ) |> AttributeDefinitionStore.registerScalar + { Key = key; Name = name }: SimpleScalarAttributeDefinition> + + let CurrentPageWithEventFn = + let name = "MultiPageOfPage_CurrentPageWithEventFn" + + let key = + SimpleScalarAttributeDefinition.CreateAttributeData( + ScalarAttributeComparers.noCompare, + (fun oldValueOpt (newValueOpt: ValueEventData voption) node -> + let target = node.Target :?> MultiPage + + match newValueOpt with + | ValueNone -> + // The attribute is no longer applied, so we clean up the event + match node.TryGetHandler(name) with + | ValueNone -> () + | ValueSome handler -> handler.Dispose() + + // Only clear the property if a value was set before + match oldValueOpt with + | ValueNone -> () + | ValueSome _ -> target.CurrentPage <- target.Children.[0] + + | ValueSome curr -> + // Clean up the old event handler if any + match node.TryGetHandler(name) with + | ValueNone -> () + | ValueSome handler -> handler.Dispose() + + // Set the new value + target.CurrentPage <- target.Children.[curr.Value] + + // Set the new event handler + let handler = + target.CurrentPageChanged.Subscribe(fun _args -> + let currentPageIndex = target.Children.IndexOf(target.CurrentPage) + curr.Event currentPageIndex) + + node.SetHandler(name, handler)) + ) + |> AttributeDefinitionStore.registerScalar + { Key = key; Name = name }: SimpleScalarAttributeDefinition> [] type MultiPageOfPageModifiers = - /// Listen for the CurrentPageChanged event - /// Current widget - /// Message to dispatch - [] - static member inline onCurrentPageChanged(this: WidgetBuilder<'msg, #IFabMultiPageOfPage>, msg: 'msg) = - this.AddScalar(MultiPageOfPage.CurrentPageChanged.WithValue(MsgValue(msg))) - /// Set the current page and listen for changes /// Current widget /// The current page index /// Function to invoke [] static member inline currentPage(this: WidgetBuilder<'msg, #IFabMultiPageOfPage>, currentPage: int, onCurrentPageChanged: int -> 'msg) = - this.AddScalar(MultiPageOfPage.CurrentPageWithEvent.WithValue(ValueEventData.create currentPage onCurrentPageChanged)) + this.AddScalar(MultiPageOfPage.CurrentPageWithEventMsg.WithValue(MsgValueEventData.create currentPage onCurrentPageChanged)) + + /// Set the current page and listen for changes + /// Current widget + /// The current page index + /// Function to invoke + [] + static member inline currentPage(this: WidgetBuilder<'msg, #IFabMultiPageOfPage>, currentPage: int, onCurrentPageChanged: int -> unit) = + this.AddScalar(MultiPageOfPage.CurrentPageWithEventFn.WithValue(ValueEventData.create currentPage onCurrentPageChanged)) diff --git a/src/Fabulous.MauiControls/Views/Pages/_Page.fs b/src/Fabulous.MauiControls/Views/Pages/_Page.fs index 22a1ea5..f701a5c 100644 --- a/src/Fabulous.MauiControls/Views/Pages/_Page.fs +++ b/src/Fabulous.MauiControls/Views/Pages/_Page.fs @@ -13,25 +13,37 @@ type IFabPage = inherit IFabVisualElement module Page = - let Appearing = - Attributes.defineEventNoArg "Page_Appearing" (fun target -> (target :?> Page).Appearing) + let AppearingMsg = + Attributes.defineEventNoArg "Page_AppearingMsg" (fun target -> (target :?> Page).Appearing) + + let AppearingFn = + Attributes.defineEventNoArgNoDispatch "Page_AppearingFn" (fun target -> (target :?> Page).Appearing) let BackgroundImageSource = Attributes.defineBindableImageSource Page.BackgroundImageSourceProperty - let Disappearing = - Attributes.defineEventNoArg "Page_Disappearing" (fun target -> (target :?> Page).Disappearing) + let DisappearingMsg = + Attributes.defineEventNoArg "Page_DisappearingMsg" (fun target -> (target :?> Page).Disappearing) + + let DisappearingFn = + Attributes.defineEventNoArgNoDispatch "Page_DisappearingFn" (fun target -> (target :?> Page).Disappearing) let IconImageSource = Attributes.defineBindableImageSource Page.IconImageSourceProperty let IsBusy = Attributes.defineBindableBool Page.IsBusyProperty - let NavigatedTo = - Attributes.defineEvent "NavigatedTo" (fun target -> (target :?> Page).NavigatedTo) + let NavigatedToMsg = + Attributes.defineEvent "NavigatedToMsg" (fun target -> (target :?> Page).NavigatedTo) + + let NavigatedToFn = + Attributes.defineEventNoDispatch "NavigatedToFn" (fun target -> (target :?> Page).NavigatedTo) - let NavigatedFrom = - Attributes.defineEvent "NavigatedFrom" (fun target -> (target :?> Page).NavigatedFrom) + let NavigatedFromMsg = + Attributes.defineEvent "NavigatedFromMsg" (fun target -> (target :?> Page).NavigatedFrom) + + let NavigatedFromFn = + Attributes.defineEventNoDispatch "NavigatedFromFn" (fun target -> (target :?> Page).NavigatedFrom) let Padding = Attributes.defineBindableWithEquality Page.PaddingProperty @@ -79,22 +91,44 @@ type PageModifiers = /// Message to dispatch [] static member inline onAppearing(this: WidgetBuilder<'msg, #IFabPage>, msg: 'msg) = - this.AddScalar(Page.Appearing.WithValue(MsgValue(msg))) + this.AddScalar(Page.AppearingMsg.WithValue(MsgValue(msg))) + + /// Listen to the Appearing event + /// Current widget + /// Function to execute + [] + static member inline onAppearing(this: WidgetBuilder<'msg, #IFabPage>, fn: unit -> unit) = + this.AddScalar(Page.AppearingFn.WithValue(fn)) /// Listen to the Disappearing event /// Current widget /// Message to dispatch [] static member inline onDisappearing(this: WidgetBuilder<'msg, #IFabPage>, msg: 'msg) = - this.AddScalar(Page.Disappearing.WithValue(MsgValue(msg))) + this.AddScalar(Page.DisappearingMsg.WithValue(MsgValue(msg))) + + /// Listen to the Disappearing event + /// Current widget + /// Function to execute + [] + static member inline onDisappearing(this: WidgetBuilder<'msg, #IFabPage>, fn: unit -> unit) = + this.AddScalar(Page.DisappearingFn.WithValue(fn)) [] static member inline onNavigatedTo(this: WidgetBuilder<'msg, #IFabPage>, msg: 'msg) = - this.AddScalar(Page.NavigatedTo.WithValue(fun _ -> msg)) + this.AddScalar(Page.NavigatedToMsg.WithValue(fun _ -> msg)) + + [] + static member inline onNavigatedTo(this: WidgetBuilder<'msg, #IFabPage>, fn: unit -> unit) = + this.AddScalar(Page.NavigatedToFn.WithValue(fun _ -> fn())) [] static member inline onNavigatedFrom(this: WidgetBuilder<'msg, #IFabPage>, msg: 'msg) = - this.AddScalar(Page.NavigatedFrom.WithValue(fun _ -> msg)) + this.AddScalar(Page.NavigatedFromMsg.WithValue(fun _ -> msg)) + + [] + static member inline onNavigatedFrom(this: WidgetBuilder<'msg, #IFabPage>, fn: unit -> unit) = + this.AddScalar(Page.NavigatedFromFn.WithValue(fun _ -> fn())) /// Set the padding inside the widget /// Current widget @@ -113,7 +147,7 @@ type PageModifiers = /// Set the toolbar items of this page menu /// Current widget [] - static member inline toolbarItems<'msg, 'marker when 'marker :> IFabPage>(this: WidgetBuilder<'msg, 'marker>) = + static member inline toolbarItems<'msg, 'marker when 'msg : equality and 'marker :> IFabPage>(this: WidgetBuilder<'msg, 'marker>) = WidgetHelpers.buildAttributeCollection<'msg, 'marker, IFabToolbarItem> Page.ToolbarItems this [] diff --git a/src/Fabulous.MauiControls/Views/Shapes/Ellipse.fs b/src/Fabulous.MauiControls/Views/Shapes/Ellipse.fs index f9f755e..d76e2f7 100644 --- a/src/Fabulous.MauiControls/Views/Shapes/Ellipse.fs +++ b/src/Fabulous.MauiControls/Views/Shapes/Ellipse.fs @@ -3,7 +3,6 @@ namespace Fabulous.Maui open System.Runtime.CompilerServices open Fabulous open Fabulous.StackAllocatedCollections.StackList -open Microsoft.Maui.Controls open Microsoft.Maui.Controls.Shapes type IFabEllipse = @@ -17,7 +16,7 @@ module EllipseBuilders = type Fabulous.Maui.View with /// Create an Ellipse widget - static member inline Ellipse<'msg>() = + static member inline Ellipse() = WidgetBuilder<'msg, IFabEllipse>(Ellipse.WidgetKey, AttributesBundle(StackList.empty(), ValueNone, ValueNone)) [] diff --git a/src/Fabulous.MauiControls/Views/Shapes/Geometries/EllipseGeometry.fs b/src/Fabulous.MauiControls/Views/Shapes/Geometries/EllipseGeometry.fs index 053acf1..8aed3d6 100644 --- a/src/Fabulous.MauiControls/Views/Shapes/Geometries/EllipseGeometry.fs +++ b/src/Fabulous.MauiControls/Views/Shapes/Geometries/EllipseGeometry.fs @@ -26,7 +26,7 @@ module EllipseGeometryBuilders = /// The center point /// The X component of the radius /// The Y component of the radius - static member inline EllipseGeometry<'msg>(center: Point, radiusX: float, radiusY: float) = + static member inline EllipseGeometry(center: Point, radiusX: float, radiusY: float) = WidgetBuilder<'msg, IFabEllipseGeometry>( EllipseGeometry.WidgetKey, EllipseGeometry.Center.WithValue(center), diff --git a/src/Fabulous.MauiControls/Views/Shapes/Geometries/GeometryGroup.fs b/src/Fabulous.MauiControls/Views/Shapes/Geometries/GeometryGroup.fs index c6c64c1..3da6712 100644 --- a/src/Fabulous.MauiControls/Views/Shapes/Geometries/GeometryGroup.fs +++ b/src/Fabulous.MauiControls/Views/Shapes/Geometries/GeometryGroup.fs @@ -23,12 +23,12 @@ module GeometryGroupBuilders = type Fabulous.Maui.View with /// Create a GeometryGroup - static member inline GeometryGroup<'msg>() = + static member inline GeometryGroup() = CollectionBuilder<'msg, IFabGeometryGroup, IFabGeometry>(GeometryGroup.WidgetKey, GeometryGroup.Children) /// Create a GeometryGroup with a fill rule /// The fill rule - static member inline GeometryGroup<'msg>(fillRule: FillRule) = + static member inline GeometryGroup(fillRule: FillRule) = CollectionBuilder<'msg, IFabGeometryGroup, IFabGeometry>( GeometryGroup.WidgetKey, GeometryGroup.Children, diff --git a/src/Fabulous.MauiControls/Views/Shapes/Geometries/LineGeometry.fs b/src/Fabulous.MauiControls/Views/Shapes/Geometries/LineGeometry.fs index 6c04b2d..9c86b3b 100644 --- a/src/Fabulous.MauiControls/Views/Shapes/Geometries/LineGeometry.fs +++ b/src/Fabulous.MauiControls/Views/Shapes/Geometries/LineGeometry.fs @@ -24,7 +24,7 @@ module LineGeometryBuilders = /// Create a LineGeometry widget with a start point and an end point /// The start point /// The end point - static member inline LineGeometry<'msg>(startPoint: Point, endPoint: Point) = + static member inline LineGeometry(startPoint: Point, endPoint: Point) = WidgetBuilder<'msg, IFabLineGeometry>( LineGeometry.WidgetKey, LineGeometry.StartPoint.WithValue(startPoint), diff --git a/src/Fabulous.MauiControls/Views/Shapes/Geometries/PathGeometry.fs b/src/Fabulous.MauiControls/Views/Shapes/Geometries/PathGeometry.fs index e178e40..9922c32 100644 --- a/src/Fabulous.MauiControls/Views/Shapes/Geometries/PathGeometry.fs +++ b/src/Fabulous.MauiControls/Views/Shapes/Geometries/PathGeometry.fs @@ -31,12 +31,12 @@ module PathGeometryBuilders = type Fabulous.Maui.View with /// Create a PathGeometry widget - static member inline PathGeometry<'msg>() = + static member inline PathGeometry() = CollectionBuilder<'msg, IFabPathGeometry, IFabPathFigure>(PathGeometry.WidgetKey, PathGeometry.FiguresWidgets) /// Create a PathGeometry widget with the fill rule /// The fill rule - static member inline PathGeometry<'msg>(fillRule: FillRule) = + static member inline PathGeometry(fillRule: FillRule) = CollectionBuilder<'msg, IFabPathGeometry, IFabPathFigure>( PathGeometry.WidgetKey, PathGeometry.FiguresWidgets, @@ -45,13 +45,13 @@ module PathGeometryBuilders = /// Create a PathGeometry widget with a figure data string and a fill rule /// The figure data string - static member inline PathGeometry<'msg>(figures: string) = + static member inline PathGeometry(figures: string) = WidgetBuilder<'msg, IFabPathGeometry>(PathGeometry.WidgetKey, PathGeometry.FiguresString.WithValue(figures)) /// Create a PathGeometry widget with a figure data string and a fill rule /// The figure data string /// The fill rule - static member inline PathGeometry<'msg>(figures: string, fillRule: FillRule) = + static member inline PathGeometry(figures: string, fillRule: FillRule) = WidgetBuilder<'msg, IFabPathGeometry>( PathGeometry.WidgetKey, PathGeometry.FiguresString.WithValue(figures), diff --git a/src/Fabulous.MauiControls/Views/Shapes/Geometries/RectangleGeometry.fs b/src/Fabulous.MauiControls/Views/Shapes/Geometries/RectangleGeometry.fs index f2c9123..99ad8b0 100644 --- a/src/Fabulous.MauiControls/Views/Shapes/Geometries/RectangleGeometry.fs +++ b/src/Fabulous.MauiControls/Views/Shapes/Geometries/RectangleGeometry.fs @@ -20,7 +20,7 @@ module RectangleGeometryBuilders = /// Create a RectangleGeometry widget with a dimension /// The dimension value - static member inline RectangleGeometry<'msg>(rect: Rect) = + static member inline RectangleGeometry(rect: Rect) = WidgetBuilder<'msg, IFabRectangleGeometry>(RectangleGeometry.WidgetKey, RectangleGeometry.Rect.WithValue(rect)) [] diff --git a/src/Fabulous.MauiControls/Views/Shapes/Geometries/RoundRectangleGeometry.fs b/src/Fabulous.MauiControls/Views/Shapes/Geometries/RoundRectangleGeometry.fs index b2f96d1..85fdb16 100644 --- a/src/Fabulous.MauiControls/Views/Shapes/Geometries/RoundRectangleGeometry.fs +++ b/src/Fabulous.MauiControls/Views/Shapes/Geometries/RoundRectangleGeometry.fs @@ -29,7 +29,7 @@ module RoundRectangleGeometryBuilders = /// Create a RoundRectangleGeometry widget with a corner radius and a dimension /// The corner radius /// The dimension - static member inline RoundRectangleGeometry<'msg>(cornerRadius: CornerRadius, rect: Rect) = + static member inline RoundRectangleGeometry(cornerRadius: CornerRadius, rect: Rect) = WidgetBuilder<'msg, IFabRoundRectangleGeometry>( RoundRectangleGeometry.WidgetKey, RoundRectangleGeometry.CornerRadius.WithValue(cornerRadius), diff --git a/src/Fabulous.MauiControls/Views/Shapes/Line.fs b/src/Fabulous.MauiControls/Views/Shapes/Line.fs index 908609f..6303fdf 100644 --- a/src/Fabulous.MauiControls/Views/Shapes/Line.fs +++ b/src/Fabulous.MauiControls/Views/Shapes/Line.fs @@ -2,8 +2,6 @@ namespace Fabulous.Maui open System.Runtime.CompilerServices open Fabulous -open Fabulous.StackAllocatedCollections.StackList -open Microsoft.Maui.Controls open Microsoft.Maui.Controls.Shapes open Microsoft.Maui.Graphics @@ -36,7 +34,7 @@ module LineBuilders = /// Create a Line widget with a start point, an end point, a stroke thickness, and a stroke brush /// The start point /// The end point - static member inline Line<'msg>(startPoint: Point, endPoint: Point) = + static member inline Line(startPoint: Point, endPoint: Point) = WidgetBuilder<'msg, IFabLine>(Line.WidgetKey, Line.Points.WithValue(struct (startPoint, endPoint))) [] diff --git a/src/Fabulous.MauiControls/Views/Shapes/Path.fs b/src/Fabulous.MauiControls/Views/Shapes/Path.fs index d46f27e..2cb5784 100644 --- a/src/Fabulous.MauiControls/Views/Shapes/Path.fs +++ b/src/Fabulous.MauiControls/Views/Shapes/Path.fs @@ -40,7 +40,7 @@ module PathBuilders = /// Create a Path widget with a data path string /// The data path - static member inline Path<'msg>(data: string) = + static member inline Path(data: string) = WidgetBuilder<'msg, IFabPath>(Path.WidgetKey, Path.DataString.WithValue(data)) /// Create a Path widget with a Geometry widget diff --git a/src/Fabulous.MauiControls/Views/Shapes/PathTransforms/CompositeTransform.fs b/src/Fabulous.MauiControls/Views/Shapes/PathTransforms/CompositeTransform.fs index 88756ac..04afd1b 100644 --- a/src/Fabulous.MauiControls/Views/Shapes/PathTransforms/CompositeTransform.fs +++ b/src/Fabulous.MauiControls/Views/Shapes/PathTransforms/CompositeTransform.fs @@ -71,7 +71,7 @@ module CompositeTransformBuilders = /// The Y component of the scale /// The X component of the skew /// The Y component of the skew - static member inline CompositeTransform<'msg>(centerX: float, centerY: float, scaleX: float, scaleY: float, skewX: float, skewY: float) = + static member inline CompositeTransform(centerX: float, centerY: float, scaleX: float, scaleY: float, skewX: float, skewY: float) = WidgetBuilder<'msg, IFabCompositeTransform>( CompositeTransform.WidgetKey, CompositeTransform.CenterXY.WithValue(struct (centerX, centerY)), diff --git a/src/Fabulous.MauiControls/Views/Shapes/PathTransforms/MatrixTransform.fs b/src/Fabulous.MauiControls/Views/Shapes/PathTransforms/MatrixTransform.fs index c00b969..c0c8d2f 100644 --- a/src/Fabulous.MauiControls/Views/Shapes/PathTransforms/MatrixTransform.fs +++ b/src/Fabulous.MauiControls/Views/Shapes/PathTransforms/MatrixTransform.fs @@ -36,7 +36,7 @@ module MatrixTransformBuilders = /// The M22 component of the matrix transform /// The X component of the offset /// The Y component of the offset - static member inline MatrixTransform<'msg>(m11: float, m12: float, m21: float, m22: float, offsetX: float, offsetY: float) = + static member inline MatrixTransform(m11: float, m12: float, m21: float, m22: float, offsetX: float, offsetY: float) = WidgetBuilder<'msg, IFabMatrixTransform>(MatrixTransform.WidgetKey, MatrixTransform.Matrix.WithValue(struct (m11, m12, m21, m22, offsetX, offsetY))) [] diff --git a/src/Fabulous.MauiControls/Views/Shapes/PathTransforms/RotateTransform.fs b/src/Fabulous.MauiControls/Views/Shapes/PathTransforms/RotateTransform.fs index 4392b1c..6ec92da 100644 --- a/src/Fabulous.MauiControls/Views/Shapes/PathTransforms/RotateTransform.fs +++ b/src/Fabulous.MauiControls/Views/Shapes/PathTransforms/RotateTransform.fs @@ -24,7 +24,7 @@ module RotateTransformBuilders = /// The angle value /// The X position /// The Y position - static member inline RotateTransform<'msg>(angle: float, centerX: float, centerY: float) = + static member inline RotateTransform(angle: float, centerX: float, centerY: float) = WidgetBuilder<'msg, IFabRotateTransform>( RotateTransform.WidgetKey, RotateTransform.Angle.WithValue(angle), diff --git a/src/Fabulous.MauiControls/Views/Shapes/PathTransforms/ScaleTransform.fs b/src/Fabulous.MauiControls/Views/Shapes/PathTransforms/ScaleTransform.fs index 151b1da..7a0a118 100644 --- a/src/Fabulous.MauiControls/Views/Shapes/PathTransforms/ScaleTransform.fs +++ b/src/Fabulous.MauiControls/Views/Shapes/PathTransforms/ScaleTransform.fs @@ -35,7 +35,7 @@ module ScaleTransformBuilders = /// The Y component of the scale /// The X position of the center /// The Y position of the center - static member inline ScaleTransform<'msg>(scaleX: float, scaleY: float, centerX: float, centerY: float) = + static member inline ScaleTransform(scaleX: float, scaleY: float, centerX: float, centerY: float) = WidgetBuilder<'msg, IFabScaleTransform>( ScaleTransform.WidgetKey, ScaleTransform.ScaleXY.WithValue(struct (scaleX, scaleY)), diff --git a/src/Fabulous.MauiControls/Views/Shapes/PathTransforms/SkewTransform.fs b/src/Fabulous.MauiControls/Views/Shapes/PathTransforms/SkewTransform.fs index a3f83bd..e5a1106 100644 --- a/src/Fabulous.MauiControls/Views/Shapes/PathTransforms/SkewTransform.fs +++ b/src/Fabulous.MauiControls/Views/Shapes/PathTransforms/SkewTransform.fs @@ -35,7 +35,7 @@ module SkewTransformBuilders = /// The Y component of the angle /// The X position of the center /// The Y position of the center - static member inline SkewTransform<'msg>(angleX: float, angleY: float, centerX: float, centerY: float) = + static member inline SkewTransform(angleX: float, angleY: float, centerX: float, centerY: float) = WidgetBuilder<'msg, IFabSkewTransform>( SkewTransform.WidgetKey, SkewTransform.AnglesXY.WithValue(struct (angleX, angleY)), diff --git a/src/Fabulous.MauiControls/Views/Shapes/PathTransforms/TransformGroup.fs b/src/Fabulous.MauiControls/Views/Shapes/PathTransforms/TransformGroup.fs index 622d384..9624feb 100644 --- a/src/Fabulous.MauiControls/Views/Shapes/PathTransforms/TransformGroup.fs +++ b/src/Fabulous.MauiControls/Views/Shapes/PathTransforms/TransformGroup.fs @@ -20,7 +20,7 @@ module TransformGroupBuilders = type Fabulous.Maui.View with /// Create a TransformGroup widget - static member inline TransformGroup<'msg>() = + static member inline TransformGroup() = CollectionBuilder<'msg, IFabTransformGroup, IFabTransform>(TransformGroup.WidgetKey, TransformGroup.Children) [] diff --git a/src/Fabulous.MauiControls/Views/Shapes/PathTransforms/TranslateTransform.fs b/src/Fabulous.MauiControls/Views/Shapes/PathTransforms/TranslateTransform.fs index eca2555..9a9be11 100644 --- a/src/Fabulous.MauiControls/Views/Shapes/PathTransforms/TranslateTransform.fs +++ b/src/Fabulous.MauiControls/Views/Shapes/PathTransforms/TranslateTransform.fs @@ -21,7 +21,7 @@ module TranslateTransformBuilders = /// Create a TranslateTransform widget with translation value /// The X component of the translation /// The Y component of the translation - static member inline TranslateTransform<'msg>(x: float, y: float) = + static member inline TranslateTransform(x: float, y: float) = WidgetBuilder<'msg, IFabTranslateTransform>(TranslateTransform.WidgetKey, TranslateTransform.X.WithValue(x), TranslateTransform.Y.WithValue(y)) [] diff --git a/src/Fabulous.MauiControls/Views/Shapes/Polygon.fs b/src/Fabulous.MauiControls/Views/Shapes/Polygon.fs index ed84081..a4eba1b 100644 --- a/src/Fabulous.MauiControls/Views/Shapes/Polygon.fs +++ b/src/Fabulous.MauiControls/Views/Shapes/Polygon.fs @@ -2,7 +2,6 @@ namespace Fabulous.Maui open System.Runtime.CompilerServices open Fabulous -open Fabulous.StackAllocatedCollections.StackList open Microsoft.Maui.Controls open Microsoft.Maui.Controls.Shapes open Microsoft.Maui.Graphics @@ -40,7 +39,7 @@ module PolygonBuilders = /// Create a Polygon widget with a list of points /// The points list - static member inline Polygon<'msg>(points: string) = + static member inline Polygon(points: string) = WidgetBuilder<'msg, IFabPolygon>(Polygon.WidgetKey, Polygon.PointsString.WithValue(points)) /// Create a Polygon widget with a list of points diff --git a/src/Fabulous.MauiControls/Views/Shapes/Polyline.fs b/src/Fabulous.MauiControls/Views/Shapes/Polyline.fs index 1c8de4f..5170fdf 100644 --- a/src/Fabulous.MauiControls/Views/Shapes/Polyline.fs +++ b/src/Fabulous.MauiControls/Views/Shapes/Polyline.fs @@ -2,7 +2,6 @@ namespace Fabulous.Maui open System.Runtime.CompilerServices open Fabulous -open Fabulous.StackAllocatedCollections.StackList open Microsoft.Maui.Controls open Microsoft.Maui.Controls.Shapes open Microsoft.Maui.Graphics @@ -43,7 +42,7 @@ module PolylineBuilders = /// Create a Polyline widget with a list of points, a stroke thickness, a stroke brush /// The points list - static member inline Polyline<'msg>(points: string) = + static member inline Polyline(points: string) = WidgetBuilder<'msg, IFabPolyline>(Polyline.WidgetKey, Polyline.PointsString.WithValue(points)) /// Create a Polyline widget with a list of points, a stroke thickness, a stroke brush diff --git a/src/Fabulous.MauiControls/Views/Shapes/Rectangle.fs b/src/Fabulous.MauiControls/Views/Shapes/Rectangle.fs index 1e3a1c6..0149237 100644 --- a/src/Fabulous.MauiControls/Views/Shapes/Rectangle.fs +++ b/src/Fabulous.MauiControls/Views/Shapes/Rectangle.fs @@ -3,7 +3,6 @@ namespace Fabulous.Maui open System.Runtime.CompilerServices open Fabulous open Fabulous.StackAllocatedCollections.StackList -open Microsoft.Maui.Controls open Microsoft.Maui.Controls.Shapes type IFabRectangle = diff --git a/src/Fabulous.MauiControls/Views/Shapes/RoundRectangle.fs b/src/Fabulous.MauiControls/Views/Shapes/RoundRectangle.fs index 54e562e..104c0f4 100644 --- a/src/Fabulous.MauiControls/Views/Shapes/RoundRectangle.fs +++ b/src/Fabulous.MauiControls/Views/Shapes/RoundRectangle.fs @@ -1,11 +1,9 @@ namespace Fabulous.Maui -open System open System.Runtime.CompilerServices open Fabulous open Microsoft.Maui open Microsoft.Maui.Controls.Shapes -open Microsoft.Maui.Graphics type IFabRoundRectangle = inherit IFabShape @@ -22,7 +20,7 @@ module RoundRectangleBuilders = /// Create a RoundRectangle widget with a corner radius /// The corner radius - static member inline RoundRectangle<'msg>(cornerRadius: CornerRadius) = + static member inline RoundRectangle(cornerRadius: CornerRadius) = WidgetBuilder<'msg, IFabRoundRectangle>(RoundRectangle.WidgetKey, RoundRectangle.CornerRadius.WithValue(cornerRadius)) [] diff --git a/src/Fabulous.MauiControls/Views/Shapes/Segments/ArcSegment.fs b/src/Fabulous.MauiControls/Views/Shapes/Segments/ArcSegment.fs index e4501dd..a380a81 100644 --- a/src/Fabulous.MauiControls/Views/Shapes/Segments/ArcSegment.fs +++ b/src/Fabulous.MauiControls/Views/Shapes/Segments/ArcSegment.fs @@ -30,7 +30,7 @@ module ArcSegmentBuilders = /// Create a ArcSegment widget /// The point /// The size - static member inline ArcSegment<'msg>(point: Point, size: Size) = + static member inline ArcSegment(point: Point, size: Size) = WidgetBuilder<'msg, IFabArcSegment>(ArcSegment.WidgetKey, ArcSegment.Point.WithValue(point), ArcSegment.Size.WithValue(size)) [] diff --git a/src/Fabulous.MauiControls/Views/Shapes/Segments/BezierSegment.fs b/src/Fabulous.MauiControls/Views/Shapes/Segments/BezierSegment.fs index 28e303d..3a68346 100644 --- a/src/Fabulous.MauiControls/Views/Shapes/Segments/BezierSegment.fs +++ b/src/Fabulous.MauiControls/Views/Shapes/Segments/BezierSegment.fs @@ -28,7 +28,7 @@ module BezierSegmentBuilders = /// The first point /// The second point /// The third point - static member inline BezierSegment<'msg>(point1: Point, point2: Point, point3: Point) = + static member inline BezierSegment(point1: Point, point2: Point, point3: Point) = WidgetBuilder<'msg, IFabBezierSegment>( BezierSegment.WidgetKey, BezierSegment.Point1.WithValue(point1), diff --git a/src/Fabulous.MauiControls/Views/Shapes/Segments/LineSegment.fs b/src/Fabulous.MauiControls/Views/Shapes/Segments/LineSegment.fs index 2381141..6288717 100644 --- a/src/Fabulous.MauiControls/Views/Shapes/Segments/LineSegment.fs +++ b/src/Fabulous.MauiControls/Views/Shapes/Segments/LineSegment.fs @@ -19,7 +19,7 @@ module LineSegmentBuilders = /// Create a LineSegment widget with a start and end point /// The start and end point - static member inline LineSegment<'msg>(point: Point) = + static member inline LineSegment(point: Point) = WidgetBuilder<'msg, IFabLineSegment>(LineSegment.WidgetKey, LineSegment.Point.WithValue(point)) [] diff --git a/src/Fabulous.MauiControls/Views/Shapes/Segments/PathFigure.fs b/src/Fabulous.MauiControls/Views/Shapes/Segments/PathFigure.fs index 3cf7db3..e95f7fa 100644 --- a/src/Fabulous.MauiControls/Views/Shapes/Segments/PathFigure.fs +++ b/src/Fabulous.MauiControls/Views/Shapes/Segments/PathFigure.fs @@ -28,12 +28,12 @@ module PathFigureBuilders = type Fabulous.Maui.View with /// Create a PathFigure widget - static member inline PathFigure<'msg>() = + static member inline PathFigure() = CollectionBuilder<'msg, IFabPathFigure, IFabPathSegment>(PathFigure.WidgetKey, PathFigure.Segments) /// Create a PathFigure widget with a start point /// The start point - static member inline PathFigure<'msg>(startPoint: Point) = + static member inline PathFigure(startPoint: Point) = CollectionBuilder<'msg, IFabPathFigure, IFabPathSegment>(PathFigure.WidgetKey, PathFigure.Segments, PathFigure.StartPoint.WithValue(startPoint)) [] diff --git a/src/Fabulous.MauiControls/Views/Shapes/Segments/PolyBezierSegment.fs b/src/Fabulous.MauiControls/Views/Shapes/Segments/PolyBezierSegment.fs index 02bcf12..08db3a8 100644 --- a/src/Fabulous.MauiControls/Views/Shapes/Segments/PolyBezierSegment.fs +++ b/src/Fabulous.MauiControls/Views/Shapes/Segments/PolyBezierSegment.fs @@ -37,12 +37,12 @@ module PolyBezierSegmentBuilders = /// Create a PolyBezierSegment with a list of points /// The points list - static member inline PolyBezierSegment<'msg>(points: string) = + static member inline PolyBezierSegment(points: string) = WidgetBuilder<'msg, IFabPolyBezierSegment>(PolyBezierSegment.WidgetKey, PolyBezierSegment.PointsString.WithValue(points)) /// Create a PolyBezierSegment with a list of points /// The points list - static member inline PolyBezierSegment<'msg>(points: seq) = + static member inline PolyBezierSegment(points: seq) = WidgetBuilder<'msg, IFabPolyBezierSegment>(PolyBezierSegment.WidgetKey, PolyBezierSegment.PointsList.WithValue(Array.ofSeq points)) [] diff --git a/src/Fabulous.MauiControls/Views/Shapes/Segments/PolyLineSegment.fs b/src/Fabulous.MauiControls/Views/Shapes/Segments/PolyLineSegment.fs index 1da4236..75f5245 100644 --- a/src/Fabulous.MauiControls/Views/Shapes/Segments/PolyLineSegment.fs +++ b/src/Fabulous.MauiControls/Views/Shapes/Segments/PolyLineSegment.fs @@ -37,12 +37,12 @@ module PolyLineSegmentBuilders = /// Create a PolyLineSegment with a list of points /// The points list - static member inline PolyLineSegment<'msg>(points: string) = + static member inline PolyLineSegment(points: string) = WidgetBuilder<'msg, IFabPolyLineSegment>(PolyLineSegment.WidgetKey, PolyLineSegment.PointsString.WithValue(points)) /// Create a PolyLineSegment with a list of points /// The points list - static member inline PolyLineSegment<'msg>(points: seq) = + static member inline PolyLineSegment(points: seq) = WidgetBuilder<'msg, IFabPolyLineSegment>(PolyLineSegment.WidgetKey, PolyLineSegment.PointsList.WithValue(Array.ofSeq points)) [] diff --git a/src/Fabulous.MauiControls/Views/Shapes/Segments/PolyQuadraticBezierSegment.fs b/src/Fabulous.MauiControls/Views/Shapes/Segments/PolyQuadraticBezierSegment.fs index fb0700b..d418a22 100644 --- a/src/Fabulous.MauiControls/Views/Shapes/Segments/PolyQuadraticBezierSegment.fs +++ b/src/Fabulous.MauiControls/Views/Shapes/Segments/PolyQuadraticBezierSegment.fs @@ -37,12 +37,12 @@ module PolyQuadraticBezierSegmentBuilders = /// Create a PolyQuadraticBezierSegment with a list of points /// The points list - static member inline PolyQuadraticBezierSegment<'msg>(points: string) = + static member inline PolyQuadraticBezierSegment(points: string) = WidgetBuilder<'msg, IFabPolyQuadraticBezierSegment>(PolyQuadraticBezierSegment.WidgetKey, PolyQuadraticBezierSegment.PointsString.WithValue(points)) /// Create a PolyQuadraticBezierSegment with a list of points /// The points list - static member inline PolyQuadraticBezierSegment<'msg>(points: seq) = + static member inline PolyQuadraticBezierSegment(points: seq) = WidgetBuilder<'msg, IFabPolyQuadraticBezierSegment>( PolyQuadraticBezierSegment.WidgetKey, PolyQuadraticBezierSegment.PointsList.WithValue(Array.ofSeq points) diff --git a/src/Fabulous.MauiControls/Views/Shapes/Segments/QuadraticBezierSegment.fs b/src/Fabulous.MauiControls/Views/Shapes/Segments/QuadraticBezierSegment.fs index 8e48a25..4c2e4ac 100644 --- a/src/Fabulous.MauiControls/Views/Shapes/Segments/QuadraticBezierSegment.fs +++ b/src/Fabulous.MauiControls/Views/Shapes/Segments/QuadraticBezierSegment.fs @@ -24,7 +24,7 @@ module QuadraticBezierSegmentBuilders = /// Create a QuadraticBezierSegment with a list of points /// The first point /// The second point - static member inline QuadraticBezierSegment<'msg>(point1: Point, point2: Point) = + static member inline QuadraticBezierSegment(point1: Point, point2: Point) = WidgetBuilder<'msg, IFabQuadraticBezierSegment>( QuadraticBezierSegment.WidgetKey, QuadraticBezierSegment.Point1.WithValue(point1), diff --git a/src/Fabulous.MauiControls/Views/Window.fs b/src/Fabulous.MauiControls/Views/Window.fs index c2be08b..ced1b2d 100644 --- a/src/Fabulous.MauiControls/Views/Window.fs +++ b/src/Fabulous.MauiControls/Views/Window.fs @@ -30,32 +30,59 @@ module Window = let MinimumWidth = Attributes.defineBindableWithEquality Window.MinimumWidthProperty - let Activated = - Attributes.defineEventNoArg "Window_Activated" (fun target -> (target :?> Window).Activated) + let ActivatedMsg = + Attributes.defineEventNoArg "Window_ActivatedMsg" (fun target -> (target :?> Window).Activated) - let Backgrounding = - Attributes.defineEvent "Window_Backgrounding" (fun target -> (target :?> Window).Backgrounding) + let ActivatedFn = + Attributes.defineEventNoArgNoDispatch "Window_ActivatedFn" (fun target -> (target :?> Window).Activated) - let Created = - Attributes.defineEventNoArg "Window_Created" (fun target -> (target :?> Window).Created) + let BackgroundingMsg = + Attributes.defineEvent "Window_BackgroundingMsg" (fun target -> (target :?> Window).Backgrounding) - let Deactivated = - Attributes.defineEventNoArg "Window_Deactivated" (fun target -> (target :?> Window).Deactivated) + let BackgroundingFn = + Attributes.defineEventNoDispatch "Window_BackgroundingFn" (fun target -> (target :?> Window).Backgrounding) - let Destroying = - Attributes.defineEventNoArg "Window_Destroying" (fun target -> (target :?> Window).Destroying) + let CreatedMsg = + Attributes.defineEventNoArg "Window_CreatedMsg" (fun target -> (target :?> Window).Created) - let DisplayDensityChanged = - Attributes.defineEvent "Window_DisplayDensityChanged" (fun target -> (target :?> Window).DisplayDensityChanged) + let CreatedFn = + Attributes.defineEventNoArgNoDispatch "Window_CreatedFn" (fun target -> (target :?> Window).Created) - let SizeChanged = - Attributes.defineEventNoArg "Window_SizeChanged" (fun target -> (target :?> Window).SizeChanged) + let DeactivatedMsg = + Attributes.defineEventNoArg "Window_DeactivatedMsg" (fun target -> (target :?> Window).Deactivated) - let Resumed = - Attributes.defineEventNoArg "Window_Resumed" (fun target -> (target :?> Window).Resumed) + let DeactivatedFn = + Attributes.defineEventNoArgNoDispatch "Window_DeactivatedFn" (fun target -> (target :?> Window).Deactivated) - let Stopped = - Attributes.defineEventNoArg "Window_Stopped" (fun target -> (target :?> Window).Stopped) + let DestroyingMsg = + Attributes.defineEventNoArg "Window_DestroyingMsg" (fun target -> (target :?> Window).Destroying) + + let DestroyingFn = + Attributes.defineEventNoArgNoDispatch "Window_DestroyingFn" (fun target -> (target :?> Window).Destroying) + + let DisplayDensityChangedMsg = + Attributes.defineEvent "Window_DisplayDensityChangedMsg" (fun target -> (target :?> Window).DisplayDensityChanged) + + let DisplayDensityChangedFn = + Attributes.defineEventNoDispatch "Window_DisplayDensityChangedFn" (fun target -> (target :?> Window).DisplayDensityChanged) + + let SizeChangedMsg = + Attributes.defineEventNoArg "Window_SizeChangedMsg" (fun target -> (target :?> Window).SizeChanged) + + let SizeChangedFn = + Attributes.defineEventNoArgNoDispatch "Window_SizeChangedFn" (fun target -> (target :?> Window).SizeChanged) + + let ResumedMsg = + Attributes.defineEventNoArg "Window_ResumedMsg" (fun target -> (target :?> Window).Resumed) + + let ResumedFn = + Attributes.defineEventNoArgNoDispatch "Window_ResumedFn" (fun target -> (target :?> Window).Resumed) + + let StoppedMsg = + Attributes.defineEventNoArg "Window_StoppedMsg" (fun target -> (target :?> Window).Stopped) + + let StoppedFn = + Attributes.defineEventNoArgNoDispatch "Window_StoppedFn" (fun target -> (target :?> Window).Stopped) let Title = Attributes.defineBindableWithEquality Window.TitleProperty @@ -103,39 +130,75 @@ type WindowModifiers = [] static member inline onActivated(this: WidgetBuilder<'msg, #IFabWindow>, msg: 'msg) = - this.AddScalar(Window.Activated.WithValue(MsgValue msg)) + this.AddScalar(Window.ActivatedMsg.WithValue(MsgValue msg)) + + [] + static member inline onActivated(this: WidgetBuilder<'msg, #IFabWindow>, fn: unit -> unit) = + this.AddScalar(Window.ActivatedFn.WithValue(fn)) [] static member inline onBackgrounding(this: WidgetBuilder<'msg, #IFabWindow>, fn: BackgroundingEventArgs -> 'msg) = - this.AddScalar(Window.Backgrounding.WithValue(fn)) + this.AddScalar(Window.BackgroundingMsg.WithValue(fn)) + + [] + static member inline onBackgrounding(this: WidgetBuilder<'msg, #IFabWindow>, fn: BackgroundingEventArgs -> unit) = + this.AddScalar(Window.BackgroundingFn.WithValue(fn)) [] static member inline onCreated(this: WidgetBuilder<'msg, #IFabWindow>, msg: 'msg) = - this.AddScalar(Window.Created.WithValue(MsgValue msg)) + this.AddScalar(Window.CreatedMsg.WithValue(MsgValue msg)) + + [] + static member inline onCreated(this: WidgetBuilder<'msg, #IFabWindow>, fn: unit -> unit) = + this.AddScalar(Window.CreatedFn.WithValue(fn)) [] static member inline onDeactivated(this: WidgetBuilder<'msg, #IFabWindow>, msg: 'msg) = - this.AddScalar(Window.Deactivated.WithValue(MsgValue msg)) + this.AddScalar(Window.DeactivatedMsg.WithValue(MsgValue msg)) + + [] + static member inline onDeactivated(this: WidgetBuilder<'msg, #IFabWindow>, fn: unit -> unit) = + this.AddScalar(Window.DeactivatedFn.WithValue(fn)) [] static member inline onDestroying(this: WidgetBuilder<'msg, #IFabWindow>, msg: 'msg) = - this.AddScalar(Window.Destroying.WithValue(MsgValue msg)) + this.AddScalar(Window.DestroyingMsg.WithValue(MsgValue msg)) + + [] + static member inline onDestroying(this: WidgetBuilder<'msg, #IFabWindow>, fn: unit -> unit) = + this.AddScalar(Window.DestroyingFn.WithValue(fn)) [] static member inline onDisplayDensityChanged(this: WidgetBuilder<'msg, #IFabWindow>, fn: DisplayDensityChangedEventArgs -> 'msg) = - this.AddScalar(Window.DisplayDensityChanged.WithValue(fn)) + this.AddScalar(Window.DisplayDensityChangedMsg.WithValue(fn)) + + [] + static member inline onDisplayDensityChanged(this: WidgetBuilder<'msg, #IFabWindow>, fn: DisplayDensityChangedEventArgs -> unit) = + this.AddScalar(Window.DisplayDensityChangedFn.WithValue(fn)) [] static member inline onSizeChanged(this: WidgetBuilder<'msg, #IFabWindow>, msg: 'msg) = - this.AddScalar(Window.SizeChanged.WithValue(MsgValue msg)) + this.AddScalar(Window.SizeChangedMsg.WithValue(MsgValue msg)) + + [] + static member inline onSizeChanged(this: WidgetBuilder<'msg, #IFabWindow>, fn: unit -> unit) = + this.AddScalar(Window.SizeChangedFn.WithValue(fn)) [] static member inline onResumed(this: WidgetBuilder<'msg, #IFabWindow>, msg: 'msg) = - this.AddScalar(Window.Resumed.WithValue(MsgValue msg)) + this.AddScalar(Window.ResumedMsg.WithValue(MsgValue msg)) + + [] + static member inline onResumed(this: WidgetBuilder<'msg, #IFabWindow>, fn: unit -> unit) = + this.AddScalar(Window.ResumedFn.WithValue(fn)) [] static member inline onStopped(this: WidgetBuilder<'msg, #IFabWindow>, msg: 'msg) = - this.AddScalar(Window.Stopped.WithValue(MsgValue msg)) + this.AddScalar(Window.StoppedMsg.WithValue(MsgValue msg)) + + [] + static member inline onStopped(this: WidgetBuilder<'msg, #IFabWindow>, fn: unit -> unit) = + this.AddScalar(Window.StoppedFn.WithValue(fn)) [] static member inline title(this: WidgetBuilder<'msg, #IFabWindow>, value: string) = diff --git a/src/Fabulous.MauiControls/Views/_View.fs b/src/Fabulous.MauiControls/Views/_View.fs index 57956ad..3b12574 100644 --- a/src/Fabulous.MauiControls/Views/_View.fs +++ b/src/Fabulous.MauiControls/Views/_View.fs @@ -26,7 +26,7 @@ type ViewModifiers = /// Set the gesture recognizers associated with this widget /// Current widget [] - static member inline gestureRecognizers<'msg, 'marker when 'marker :> IFabView>(this: WidgetBuilder<'msg, 'marker>) = + static member inline gestureRecognizers<'msg, 'marker when 'msg : equality and 'marker :> IFabView>(this: WidgetBuilder<'msg, 'marker>) = WidgetHelpers.buildAttributeCollection<'msg, 'marker, IFabGestureRecognizer> View'.GestureRecognizers this /// Set the LayoutOptions that define how the widget gets laid in a layout cycle diff --git a/src/Fabulous.MauiControls/Views/_VisualElement.fs b/src/Fabulous.MauiControls/Views/_VisualElement.fs index 60427c8..c628b28 100644 --- a/src/Fabulous.MauiControls/Views/_VisualElement.fs +++ b/src/Fabulous.MauiControls/Views/_VisualElement.fs @@ -34,7 +34,61 @@ type RotateToData = Easing: Easing } module VisualElementUpdaters = - let updateVisualElementFocus oldValueOpt (newValueOpt: ValueEventData voption) (node: IViewNode) = + let updateVisualElementFocusFn oldValueOpt (newValueOpt: ValueEventData voption) (node: IViewNode) = + let target = node.Target :?> VisualElement + + let onEventName = "Focus_On" + let offEventName = "Focus_Off" + + match newValueOpt with + | ValueNone -> + // The attribute is no longer applied, so we clean up the events + match node.TryGetHandler(onEventName) with + | ValueNone -> () + | ValueSome handler -> handler.Dispose() + + match node.TryGetHandler(offEventName) with + | ValueNone -> () + | ValueSome handler -> handler.Dispose() + + // Only clear the property if a value was set before + match oldValueOpt with + | ValueNone -> () + | ValueSome _ -> + if target.IsFocused then + target.Unfocus() + + | ValueSome curr -> + // Clean up the old event handlers if any + match node.TryGetHandler(onEventName) with + | ValueNone -> () + | ValueSome handler -> handler.Dispose() + + match node.TryGetHandler(offEventName) with + | ValueNone -> () + | ValueSome handler -> handler.Dispose() + + // Set the new value + if target.IsFocused <> curr.Value then + if curr.Value then + target.Focus() |> ignore + else + target.Unfocus() + + // Set the new event handlers + let onHandler = + target.Focused.Subscribe(fun _args -> + curr.Event true) + + node.SetHandler(onEventName, onHandler) + + let offHandler = + target.Unfocused.Subscribe(fun _args -> + curr.Event false) + + node.SetHandler(offEventName, offHandler) + + let updateVisualElementFocusMsg oldValueOpt (newValueOpt: MsgValueEventData voption) (node: IViewNode) = let target = node.Target :?> VisualElement let onEventName = "Focus_On" @@ -106,8 +160,11 @@ module VisualElement = let FlowDirection = Attributes.defineBindableEnum VisualElement.FlowDirectionProperty - let FocusWithEvent = - Attributes.defineSimpleScalar "VisualElement_FocusWithEvent" ScalarAttributeComparers.noCompare VisualElementUpdaters.updateVisualElementFocus + let FocusWithEventMsg = + Attributes.defineSimpleScalar "VisualElement_FocusWithEventMsg" ScalarAttributeComparers.noCompare VisualElementUpdaters.updateVisualElementFocusMsg + + let FocusWithEventFn = + Attributes.defineSimpleScalar "VisualElement_FocusWithEventFn" ScalarAttributeComparers.noCompare VisualElementUpdaters.updateVisualElementFocusFn let HeightRequest = Attributes.defineBindableFloat VisualElement.HeightRequestProperty @@ -257,8 +314,16 @@ type VisualElementModifiers = /// The focus state to apply /// Message to dispatch when the widget's focus state changes [] - static member inline focus(this: WidgetBuilder<'msg, #IFabVisualElement>, value: bool, onFocusChanged: bool -> 'msg) = - this.AddScalar(VisualElement.FocusWithEvent.WithValue(ValueEventData.create value onFocusChanged)) + static member inline focus<'msg, 'marker when 'msg : equality and 'marker :> IFabVisualElement>(this: WidgetBuilder<'msg, 'marker>, value: bool, onFocusChanged: bool -> 'msg) = + this.AddScalar(VisualElement.FocusWithEventMsg.WithValue(MsgValueEventData.create value onFocusChanged)) + + /// Set the current focus state of the widget, and listen to focus state changes + /// Current widget + /// The focus state to apply + /// Message to dispatch when the widget's focus state changes + [] + static member inline focus(this: WidgetBuilder<'msg, #IFabVisualElement>, value: bool, onFocusChanged: bool -> unit) = + this.AddScalar(VisualElement.FocusWithEventFn.WithValue(ValueEventData.create value onFocusChanged)) /// Set the layout flow direction /// Current widget diff --git a/src/Fabulous.MauiControls/Widgets.fs b/src/Fabulous.MauiControls/Widgets.fs index bf0d31c..6d0fac7 100644 --- a/src/Fabulous.MauiControls/Widgets.fs +++ b/src/Fabulous.MauiControls/Widgets.fs @@ -5,7 +5,6 @@ open Fabulous open Fabulous.ScalarAttributeDefinitions open Fabulous.WidgetCollectionAttributeDefinitions open Fabulous.StackAllocatedCollections.StackList -open Fabulous.StackAllocatedCollections open Fabulous.Maui open Microsoft.FSharp.Core @@ -73,16 +72,16 @@ module WidgetHelpers = let inline compileSeq (items: seq>) = items |> Seq.map(fun item -> item.Compile()) |> Seq.toArray - let inline buildWidgets<'msg, 'marker> (key: WidgetKey) (attrs: WidgetAttribute[]) = + let inline buildWidgets<'msg, 'marker when 'msg : equality> (key: WidgetKey) (attrs: WidgetAttribute[]) = WidgetBuilder<'msg, 'marker>(key, struct (StackList.empty(), ValueSome attrs, ValueNone)) - let inline buildAttributeCollection<'msg, 'marker, 'item> + let inline buildAttributeCollection<'msg, 'marker, 'item when 'msg : equality> (collectionAttributeDefinition: WidgetCollectionAttributeDefinition) (widget: WidgetBuilder<'msg, 'marker>) = AttributeCollectionBuilder<'msg, 'marker, 'item>(widget, collectionAttributeDefinition) - let buildItems<'msg, 'marker, 'itemData, 'itemMarker> + let buildItems<'msg, 'marker, 'itemData, 'itemMarker when 'msg : equality> key (attrDef: SimpleScalarAttributeDefinition) (items: seq<'itemData>) @@ -98,7 +97,7 @@ module WidgetHelpers = WidgetBuilder<'msg, 'marker>(key, attrDef.WithValue(data)) - let buildGroupItems<'msg, 'marker, 'groupData, 'itemData, 'groupMarker, 'itemMarker when 'groupData :> seq<'itemData>> + let buildGroupItems<'msg, 'marker, 'groupData, 'itemData, 'groupMarker, 'itemMarker when 'msg : equality and 'groupData :> seq<'itemData>> key (attrDef: SimpleScalarAttributeDefinition) (items: seq<'groupData>) @@ -114,7 +113,7 @@ module WidgetHelpers = WidgetBuilder<'msg, 'marker>(key, attrDef.WithValue(data)) - let buildGroupItemsNoFooter<'msg, 'marker, 'groupData, 'itemData, 'groupMarker, 'itemMarker when 'groupData :> seq<'itemData>> + let buildGroupItemsNoFooter<'msg, 'marker, 'groupData, 'itemData, 'groupMarker, 'itemMarker when 'msg : equality and 'groupData :> seq<'itemData>> key (attrDef: SimpleScalarAttributeDefinition) (items: seq<'groupData>)