Skip to content

Commit

Permalink
.
Browse files Browse the repository at this point in the history
  • Loading branch information
edgarfgp committed Sep 8, 2024
1 parent ba87082 commit 7ad8e14
Show file tree
Hide file tree
Showing 157 changed files with 9,825 additions and 8 deletions.
20 changes: 20 additions & 0 deletions src/Fabulous.Avalonia/ComponentViews/Collections/Carousel.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace Fabulous.Avalonia.Components

open Fabulous
open Fabulous.Avalonia

type IFabComponentCarousel =
inherit IFabComponentSelectingItemsControl
inherit IFabCarousel

[<AutoOpen>]
module CarouselBuilders =
type Fabulous.Avalonia.Components.View with

/// <summary>Creates a Carousel widget.</summary>
/// <param name="items">The items to display.</param>
/// <param name="template">The template to use to render each item.</param>
static member Carousel<'msg, 'itemData, 'itemMarker when 'itemMarker :> IFabComponentControl>
(items: seq<'itemData>, template: 'itemData -> WidgetBuilder<'msg, 'itemMarker>)
=
WidgetHelpers.buildItems<'msg, IFabComponentCarousel, 'itemData, 'itemMarker> Carousel.WidgetKey ItemsControl.ItemsSourceTemplate items template
24 changes: 24 additions & 0 deletions src/Fabulous.Avalonia/ComponentViews/Collections/ListBox.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace Fabulous.Avalonia.Components

open Fabulous
open Fabulous.Avalonia

type IFabComponentListBox =
inherit IFabComponentSelectingItemsControl
inherit IFabListBox

[<AutoOpen>]
module ListBoxBuilders =
type Fabulous.Avalonia.Components.View with

/// <summary>Creates a ListBox widget.</summary>
/// <param name="items">The items to display.</param>
/// <param name="template">The template to use to render each item.</param>
static member ListBox<'msg, 'itemData, 'itemMarker when 'itemMarker :> IFabControl>
(items: seq<'itemData>, template: 'itemData -> WidgetBuilder<'msg, 'itemMarker>)
=
WidgetHelpers.buildItems<'msg, IFabComponentListBox, 'itemData, 'itemMarker> ListBox.WidgetKey ItemsControl.ItemsSourceTemplate items template

/// <summary>Creates a ListBox widget.</summary>
static member ListBox() =
CollectionBuilder<'msg, IFabComponentListBox, IFabComponentListBoxItem>(ListBox.WidgetKey, ComponentItemsControl.Items)
25 changes: 25 additions & 0 deletions src/Fabulous.Avalonia/ComponentViews/Collections/TabControl.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
namespace Fabulous.Avalonia.Components

open System.Runtime.CompilerServices
open Avalonia.Controls
open Avalonia.Layout
open Fabulous
open Fabulous.Avalonia
open Fabulous.StackAllocatedCollections

type IFabComponentTabControl =
inherit IFabComponentSelectingItemsControl
inherit IFabTabControl

[<AutoOpen>]
module ComponentTabControlBuilders =
type Fabulous.Avalonia.Components.View with

/// <summary>Creates a TabControl widget.</summary>
/// <param name="placement">The placement of the tab strip.</param>
static member TabControl(placement: Dock) =
CollectionBuilder<unit, IFabComponentTabControl, IFabComponentTabItem>(TabControl.WidgetKey, ComponentItemsControl.Items, TabControl.TabStripPlacement.WithValue(placement))

/// <summary>Creates a TabControl widget.</summary>
static member TabControl() =
CollectionBuilder<unit, IFabComponentTabControl, IFabComponentTabItem>(TabControl.WidgetKey, ComponentItemsControl.Items, TabControl.TabStripPlacement.WithValue(Dock.Top))
50 changes: 50 additions & 0 deletions src/Fabulous.Avalonia/ComponentViews/Collections/TreeView.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
namespace Fabulous.Avalonia.Components

open System.Collections
open System.Runtime.CompilerServices
open Avalonia.Controls
open Fabulous
open Fabulous.Avalonia

type IFabComponentTreeView =
inherit IFabComponentItemsControl
inherit IFabTreeView

type ComponentTreeWidgetItems =
{ Nodes: IEnumerable
SubNodesFn: obj -> IEnumerable
Template: obj -> Widget }

module ComponentTreeView =
let SelectionChanged =
ComponentAttributes.defineEvent "TreeView_SelectionChanged" (fun target -> (target :?> TreeView).SelectionChanged)

[<AutoOpen>]
module ComponentTreeViewBuilders =
type Fabulous.Avalonia.Components.View with

/// <summary>Creates a TreeView widget.</summary>
/// <param name="nodes">The root nodes used to populate the TreeView.</param>
/// <param name="subNodes">The sub nodes used to populate the children of each node.</param>
/// <param name="template">The template used to render each node.</param>
static member TreeView<'msg, 'itemData, 'itemMarker when 'itemMarker :> IFabComponentControl>
(nodes: seq<'itemData>, subNodes: 'itemData -> seq<'itemData>, template: 'itemData -> WidgetBuilder<unit, 'itemMarker>)
=
let template (item: obj) =
let item = unbox<'itemData> item
(template item).Compile()

let data: TreeWidgetItems =
{ Nodes = nodes
SubNodesFn = (fun subNode -> subNodes(unbox subNode) :> IEnumerable)
Template = template }

WidgetBuilder<'msg, IFabComponentTreeView>(TreeView.WidgetKey, TreeView.ItemsSource.WithValue(data))

type ComponentTreeViewModifiers =
/// <summary>Listens to the TreeView SelectionChanged event.</summary>
/// <param name="this">Current widget.</param>
/// <param name="fn">Raised when the TreeView SelectionChanged event is fired.</param>
[<Extension>]
static member inline onSelectionChanged(this: WidgetBuilder<unit, #IFabComponentTreeView>, fn: SelectionChangedEventArgs -> unit) =
this.AddScalar(ComponentTreeView.SelectionChanged.WithValue(fn))
237 changes: 237 additions & 0 deletions src/Fabulous.Avalonia/ComponentViews/Controls/AutoCompleteBox.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
namespace Fabulous.Avalonia.Components

open System
open System.Runtime.CompilerServices
open System.Threading
open System.Threading.Tasks
open Avalonia.Controls
open Fabulous

type IFabAutoCompleteBox =
inherit IFabTemplatedControl

module AutoCompleteBox =
let WidgetKey = Widgets.register<AutoCompleteBox>()

let Watermark =
Attributes.defineAvaloniaPropertyWithEquality AutoCompleteBox.WatermarkProperty

let MinimumPrefixLength =
Attributes.defineAvaloniaPropertyWithEquality AutoCompleteBox.MinimumPrefixLengthProperty

let MinimumPopulateDelay =
Attributes.defineAvaloniaPropertyWithEquality AutoCompleteBox.MinimumPopulateDelayProperty

let MaxDropDownHeight =
Attributes.defineAvaloniaPropertyWithEquality AutoCompleteBox.MaxDropDownHeightProperty

let IsTextCompletionEnabled =
Attributes.defineAvaloniaPropertyWithEquality AutoCompleteBox.IsTextCompletionEnabledProperty

let FilterMode =
Attributes.defineAvaloniaPropertyWithEquality AutoCompleteBox.FilterModeProperty

let ItemFilter =
Attributes.defineAvaloniaPropertyWithEquality AutoCompleteBox.ItemFilterProperty

let TextFilter =
Attributes.defineAvaloniaPropertyWithEquality AutoCompleteBox.TextFilterProperty

let ItemSelector =
Attributes.defineAvaloniaPropertyWithEquality AutoCompleteBox.ItemSelectorProperty

let TextSelector =
Attributes.defineAvaloniaPropertyWithEquality AutoCompleteBox.TextSelectorProperty

let ItemsSource =
Attributes.defineAvaloniaPropertyWithEquality AutoCompleteBox.ItemsSourceProperty

let AsyncPopulator =
Attributes.defineAvaloniaPropertyWithEquality AutoCompleteBox.AsyncPopulatorProperty

let Text =
Attributes.defineAvaloniaPropertyWithChangedEvent' "AutoCompleteBox_TextChanged" AutoCompleteBox.TextProperty

let Populating =
Attributes.defineEvent<PopulatingEventArgs> "AutoCompleteBox_Populating" (fun target -> (target :?> AutoCompleteBox).Populating)

let Populated =
Attributes.defineEvent<PopulatedEventArgs> "AutoCompleteBox_Populated" (fun target -> (target :?> AutoCompleteBox).Populated)

let DropDownOpened =
Attributes.defineAvaloniaPropertyWithChangedEvent' "AutoCompleteBox_onDropDownOpened" AutoCompleteBox.IsDropDownOpenProperty

let SelectionChanged =
Attributes.defineEvent<SelectionChangedEventArgs> "AutoCompleteBox_SelectionChanged" (fun target -> (target :?> AutoCompleteBox).SelectionChanged)

/// Allows multi-binding the ValueMemberBinding on an AutoCompleteBox
let MultiValueBinding =
Attributes.defineSimpleScalar<string * string array>
"AutoCompleteBox_MultiValueBinding"
ScalarAttributeComparers.equalityCompare
(fun _ newValueOpt node ->
if newValueOpt.IsSome then
let format, propertyNames = newValueOpt.Value
let target = node.Target :?> AutoCompleteBox

let rec bindAndCleanUp _ _ =
target.multiBind<AutoCompleteBox>((fun (box: AutoCompleteBox) -> box.ValueMemberBinding), format, propertyNames)
target.Loaded.RemoveHandler(bindAndCleanUp) // to clean up

target.Loaded.AddHandler(bindAndCleanUp))

/// Allows setting the ItemTemplate on an AutoCompleteBox
let ItemTemplate =
Attributes.defineSimpleScalar<obj -> Widget> "AutoCompleteBox_ItemTemplate" ScalarAttributeComparers.physicalEqualityCompare (fun _ newValueOpt node ->
let autoComplete = node.Target :?> AutoCompleteBox

match newValueOpt with
| ValueNone -> autoComplete.ClearValue(AutoCompleteBox.ItemTemplateProperty)
| ValueSome template ->
autoComplete.SetValue(AutoCompleteBox.ItemTemplateProperty, WidgetDataTemplate(node, template))
|> ignore)

[<AutoOpen>]
module AutoCompleteBoxBuilders =
type Fabulous.Avalonia.View with

/// <summary>Creates an AutoCompleteBox widget.</summary>
/// <param name="items">The items to display.</param>
static member AutoCompleteBox(items: seq<_>) =
WidgetBuilder<'msg, IFabAutoCompleteBox>(AutoCompleteBox.WidgetKey, AutoCompleteBox.ItemsSource.WithValue(items))

/// <summary>Creates an AutoCompleteBox widget.</summary>
/// <param name="populator">The function to populate the items.</param>
static member AutoCompleteBox(populator: string -> CancellationToken -> Task<seq<_>>) =
WidgetBuilder<'msg, IFabAutoCompleteBox>(AutoCompleteBox.WidgetKey, AutoCompleteBox.AsyncPopulator.WithValue(populator))

type AutoCompleteBoxModifiers =
/// <summary>Sets the MinimumPrefixLength property.</summary>
/// <param name="this">Current widget.</param>
/// <param name="value">The MinimumPrefixLength value.</param>
[<Extension>]
static member inline minimumPrefixLength(this: WidgetBuilder<'msg, #IFabAutoCompleteBox>, value: int) =
this.AddScalar(AutoCompleteBox.MinimumPrefixLength.WithValue(value))

/// <summary>Sets the MinimumPopulateDelay property.</summary>
/// <param name="this">Current widget.</param>
/// <param name="value">The MinimumPopulateDelay value.</param>
[<Extension>]
static member inline minimumPopulateDelay(this: WidgetBuilder<'msg, #IFabAutoCompleteBox>, value: TimeSpan) =
this.AddScalar(AutoCompleteBox.MinimumPopulateDelay.WithValue(value))

/// <summary>Sets the MaxDropDownHeight property.</summary>
/// <param name="this">Current widget.</param>
/// <param name="value">The MaxDropDownHeight value.</param>
[<Extension>]
static member inline maxDropDownHeight(this: WidgetBuilder<'msg, #IFabAutoCompleteBox>, value: float) =
this.AddScalar(AutoCompleteBox.MaxDropDownHeight.WithValue(value))

/// <summary>Sets the IsTextCompletionEnabled property.</summary>
/// <param name="this">Current widget.</param>
/// <param name="value">The IsTextCompletionEnabled value.</param>
[<Extension>]
static member inline isTextCompletionEnabled(this: WidgetBuilder<'msg, #IFabAutoCompleteBox>, value: bool) =
this.AddScalar(AutoCompleteBox.IsTextCompletionEnabled.WithValue(value))

/// <summary>Sets the Watermark property.</summary>
/// <param name="this">Current widget.</param>
/// <param name="value">The Watermark value.</param>
[<Extension>]
static member inline watermark(this: WidgetBuilder<'msg, #IFabAutoCompleteBox>, value: string) =
this.AddScalar(AutoCompleteBox.Watermark.WithValue(value))

/// <summary>Sets the FilterMode property.</summary>
/// <param name="this">Current widget.</param>
/// <param name="value">The FilterMode value.</param>
[<Extension>]
static member inline filterMode(this: WidgetBuilder<'msg, #IFabAutoCompleteBox>, value: AutoCompleteFilterMode) =
this.AddScalar(AutoCompleteBox.FilterMode.WithValue(value))

/// <summary>Sets the ItemFilter property.</summary>
/// <param name="this">Current widget.</param>
/// <param name="fn">The ItemFilter value.</param>
[<Extension>]
static member inline itemFilter(this: WidgetBuilder<'msg, #IFabAutoCompleteBox>, fn: string -> obj -> bool) =
this.AddScalar(AutoCompleteBox.ItemFilter.WithValue(fn))

/// <summary>Sets the ItemTemplate property.</summary>
/// <param name="this">Current widget.</param>
/// <param name="template">The template to render the items with.</param>
[<Extension>]
static member inline itemTemplate(this: WidgetBuilder<'msg, #IFabAutoCompleteBox>, template: 'item -> WidgetBuilder<'msg, #IFabControl>) =
this.AddScalar(AutoCompleteBox.ItemTemplate.WithValue(WidgetHelpers.compileTemplate template))

/// <summary>Sets the TextFilter property.</summary>
/// <param name="this">Current widget.</param>
/// <param name="value">The TextFilter value.</param>
[<Extension>]
static member inline textFilter(this: WidgetBuilder<'msg, #IFabAutoCompleteBox>, value: string -> string -> bool) =
this.AddScalar(AutoCompleteBox.TextFilter.WithValue(value))

/// <summary>Binds the AutoCompleteBox.TextProperty.</summary>
/// <param name="this">Current widget.</param>
/// <param name="value">The value to bind.</param>
/// <param name="fn">A function mapping the updated text to a 'msg to raise on user change.</param>
[<Extension>]
static member inline onTextChanged(this: WidgetBuilder<'msg, #IFabAutoCompleteBox>, value: string, fn: string -> 'msg) =
this.AddScalar(AutoCompleteBox.Text.WithValue(ValueEventData.create value fn))

/// <summary>Sets the AutoCompleteBox.ItemSelector property to a custom method that combines the user-entered text
/// and the selected item to return the new text input value.</summary>
/// <param name="this">Current widget.</param>
/// <param name="value">A custom method receiving the entered text as the first
/// and the selected item as the second argument and returns the updated text of the input after selection.</param>
[<Extension>]
static member inline itemSelector(this: WidgetBuilder<'msg, #IFabAutoCompleteBox>, value: string -> obj -> string) =
this.AddScalar(AutoCompleteBox.ItemSelector.WithValue(value))

/// <summary>Sets the AutoCompleteBox.TextSelector property to a custom method that combines the user-entered text
/// and the selected item's text to return the new text input value.</summary>
/// <param name="this">Current widget.</param>
/// <param name="value">A custom method receiving the entered text as the first
/// and the text of the selected item as the second argument and returns the updated text of the input after selection.</param>
[<Extension>]
static member inline textSelector(this: WidgetBuilder<'msg, #IFabAutoCompleteBox>, value: string -> string -> string) =
this.AddScalar(AutoCompleteBox.TextSelector.WithValue(value))

[<Extension>]
static member inline onPopulating(this: WidgetBuilder<'msg, #IFabAutoCompleteBox>, fn: PopulatingEventArgs -> 'msg) =
this.AddScalar(AutoCompleteBox.Populating.WithValue(fn))

/// <summary>Listens to the AutoCompleteBox Populated event.</summary>
/// <param name="this">Current widget.</param>
/// <param name="fn">Raised when the AutoCompleteBox Populated event is fired.</param>
[<Extension>]
static member inline onPopulated(this: WidgetBuilder<'msg, #IFabAutoCompleteBox>, fn: PopulatedEventArgs -> 'msg) =
this.AddScalar(AutoCompleteBox.Populated.WithValue(fn))

/// <summary>Listens to the AutoCompleteBox DropDownOpened event.</summary>
/// <param name="this">Current widget.</param>
/// <param name="isOpen">The IsOpen value.</param>
/// <param name="fn">Raised when the AutoCompleteBox DropDownOpened event is fired.</param>
[<Extension>]
static member inline onDropDownOpened(this: WidgetBuilder<'msg, #IFabAutoCompleteBox>, isOpen: bool, fn: bool -> 'msg) =
this.AddScalar(AutoCompleteBox.DropDownOpened.WithValue(ValueEventData.create isOpen fn))

/// <summary>Listens to the AutoCompleteBox SelectionChanged event.</summary>
/// <param name="this">Current widget.</param>
/// <param name="fn">Raised when the AutoCompleteBox SelectionChanged event is fired.</param>
[<Extension>]
static member inline onSelectionChanged(this: WidgetBuilder<'msg, #IFabAutoCompleteBox>, fn: SelectionChangedEventArgs -> 'msg) =
this.AddScalar(AutoCompleteBox.SelectionChanged.WithValue(fn))

/// <summary>Link a ViewRef to access the direct AutoCompleteBox control instance.</summary>
/// <param name="this">Current widget.</param>
/// <param name="value">The ViewRef instance that will receive access to the underlying control.</param>
[<Extension>]
static member inline reference(this: WidgetBuilder<'msg, IFabAutoCompleteBox>, value: ViewRef<AutoCompleteBox>) =
this.AddScalar(ViewRefAttributes.ViewRef.WithValue(value.Unbox))

/// <Summary>Allows multi-binding the ValueMemberBinding on an AutoCompleteBox.</Summary>
/// <param name="this">Current widget.</param>
/// <param name="format">The format string to use.</param>
/// <param name="propertyNames">The property names to bind.</param>
[<Extension>]
static member inline multiBindValue(this: WidgetBuilder<'msg, #IFabAutoCompleteBox>, format: string, [<ParamArray>] propertyNames: string array) =
this.AddScalar(AutoCompleteBox.MultiValueBinding.WithValue((format, propertyNames)))
26 changes: 26 additions & 0 deletions src/Fabulous.Avalonia/ComponentViews/Controls/Border.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
namespace Fabulous.Avalonia.Components

open System.Runtime.CompilerServices
open Avalonia
open Avalonia.Controls
open Avalonia.Media
open Avalonia.Media.Immutable
open Fabulous
open Fabulous.Avalonia
open Fabulous.StackAllocatedCollections.StackList

type IFabComponentBorder =
inherit IFabComponentDecorator
inherit IFabBorder

[<AutoOpen>]
module ComponentBorderBuilders =
type Fabulous.Avalonia.Components.View with

/// <summary>Creates a Border widget.</summary>
/// <param name="content">The content of the Border.</param>
static member Border(content: WidgetBuilder<unit, #IFabControl>) =
WidgetBuilder<unit, IFabComponentBorder>(
Border.WidgetKey,
AttributesBundle(StackList.empty(), ValueSome [| Decorator.ChildWidget.WithValue(content.Compile()) |], ValueNone)
)
Loading

0 comments on commit 7ad8e14

Please sign in to comment.