Skip to content

Commit

Permalink
Merge pull request #1059 from fabulous-dev/component-attach-view
Browse files Browse the repository at this point in the history
Implement Component.AttachView
  • Loading branch information
TimLariviere committed Jan 20, 2024
2 parents 1df2578 + 953d53f commit b7657aa
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 5 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

_No unreleased changes_

## [2.5.0-pre5] - 2024-01-20

### Added
- Add support for Component in frameworks requiring AttachView (like Fabulous.Avalonia) by @TimLariviere (https://github.com/fabulous-dev/Fabulous/pull/1059)

## [2.5.0-pre4] - 2024-01-18

### Changed
Expand Down Expand Up @@ -70,7 +75,8 @@ _No unreleased changes_
### Changed
- Fabulous.XamarinForms & Fabulous.MauiControls have been moved been out of the Fabulous repository. Find them in their own repositories: [https://github.com/fabulous-dev/Fabulous.XamarinForms](https://github.com/fabulous-dev/Fabulous.XamarinForms) / [https://github.com/fabulous-dev/Fabulous.MauiControls](https://github.com/fabulous-dev/Fabulous.MauiControls)

[unreleased]: https://github.com/fabulous-dev/Fabulous/compare/2.5.0-pre4...HEAD
[unreleased]: https://github.com/fabulous-dev/Fabulous/compare/2.5.0-pre5...HEAD
[2.5.0-pre5]: https://github.com/fabulous-dev/Fabulous/releases/tag/2.5.0-pre5
[2.5.0-pre4]: https://github.com/fabulous-dev/Fabulous/releases/tag/2.5.0-pre4
[2.5.0-pre3]: https://github.com/fabulous-dev/Fabulous/releases/tag/2.5.0-pre3
[2.5.0-pre2]: https://github.com/fabulous-dev/Fabulous/releases/tag/2.5.0-pre2
Expand Down
46 changes: 44 additions & 2 deletions src/Fabulous/Component.fs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,32 @@ type Component(treeContext: ViewTreeContext, body: ComponentBody, context: Compo

struct (node, view)

member this.AttachView(componentWidget: Widget, view: obj) =
let struct (context, rootWidget) = _body.Invoke(_context)
_widget <- rootWidget
_context <- context

let struct (scalars, widgets, widgetColls) =
this.MergeAttributes(rootWidget, ValueSome componentWidget)

let rootWidget: Widget =
{ Key = rootWidget.Key
#if DEBUG
DebugName = rootWidget.DebugName
#endif
ScalarAttributes = scalars
WidgetAttributes = widgets
WidgetCollectionAttributes = widgetColls }

// Attach the widget to the existing view
let widgetDef = WidgetDefinitionStore.get rootWidget.Key
let node = widgetDef.AttachView(rootWidget, treeContext, ValueNone, view)

_view <- view
_contextSubscription <- _context.RenderNeeded.Subscribe(this.Render)

node

member this.Render() =
let prevRootWidget = _widget
let prevContext = _context
Expand All @@ -304,7 +330,6 @@ module Component =
{ Key = key
Name = "Component"
TargetType = typeof<Component>
AttachView = fun _ -> failwith "Component widget cannot be attached"
CreateView =
fun (widget, treeContext, _) ->
match widget.ScalarAttributes with
Expand All @@ -321,7 +346,24 @@ module Component =

// TODO: Attach component to view so component is not discarded by GC

struct (node, view) }
struct (node, view)
AttachView =
fun (widget, treeContext, _, view) ->
match widget.ScalarAttributes with
| ValueNone -> failwith "Component widget must have a body"
| ValueSome attrs ->
let data =
match Array.tryHead attrs with
| Some attr -> attr.Value :?> ComponentData
| None -> failwith "Component widget must have a body"

let ctx = ComponentContext()
let comp = new Component(treeContext, data.Body, ctx)
let node = comp.AttachView(widget, view)

// TODO: Attach component to view so component is not discarded by GC

node }

WidgetDefinitionStore.set key definition
key
Expand Down
31 changes: 29 additions & 2 deletions src/Fabulous/MvuComponent.fs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ module MvuComponent =
{ Key = key
Name = "MvuComponent"
TargetType = typeof<Component>
AttachView = fun _ -> failwith "Component widget cannot be attached"
CreateView =
fun (widget, treeContext, _) ->
match widget.ScalarAttributes with
Expand Down Expand Up @@ -44,7 +43,35 @@ module MvuComponent =

// TODO: Attach component to view so component is not discarded by GC

struct (node, view) }
struct (node, view)
AttachView =
fun (widget, treeContext, _, view) ->
match widget.ScalarAttributes with
| ValueNone -> failwith "Component widget must have a body"
| ValueSome attrs ->
let data =
match Array.tryHead attrs with
| Some attr -> attr.Value :?> MvuComponentData
| None -> failwith "Component widget must have a body"

let ctx = ComponentContext(1)

let runner =
Runner((fun () -> ctx.TryGetValue(0).Value), (fun v -> ctx.SetValue(0, v)), data.Program)

runner.Start(data.Arg)

// Redirect messages to runner
let treeContext =
{ treeContext with
Dispatch = runner.Dispatch }

let comp = new Component(treeContext, data.Body, ctx)
let node = comp.AttachView(widget, view)

// TODO: Attach component to view so component is not discarded by GC

node }

WidgetDefinitionStore.set key definition
key
Expand Down

0 comments on commit b7657aa

Please sign in to comment.