Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add extraAttributes support #780

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions Fabulous.CodeGen/src/Fabulous.CodeGen/Generator/CodeGenerator.fs
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,18 @@ module CodeGenerator =
if immediateMembers.Length > 0 then
w.printfn ""
for m in immediateMembers do
w.printfn " let attribCount = match %s with Some _ -> attribCount + 1 | None -> attribCount" m.Name
if m.Name = "extraAttributes" then
w.printfn " let attribCount = match %s with Some extraAttributes -> attribCount + extraAttributes.Length | None -> attribCount" m.Name
else
w.printfn " let attribCount = match %s with Some _ -> attribCount + 1 | None -> attribCount" m.Name

w.printfn " let extraCount = match extraAttributes with Some extraAttributes -> extraAttributes.Length | None -> 0"
w.printfn ""


match data.BaseName with
| None ->
w.printfn " let attribBuilder = AttributesBuilder(attribCount)"
w.printfn " let attribBuilder = AttributesBuilder(attribCount, extraCount)"
| Some nameOfBaseCreator ->
let baseMemberNewLine = "\n " + String.replicate nameOfBaseCreator.Length " " + " "
let baseMembers =
Expand Down Expand Up @@ -284,7 +290,7 @@ module CodeGenerator =
w.printfn ""
w.printfn " let attribBuilder = ViewBuilders.Build%s(0%s)" data.Name membersForBuild
w.printfn ""
w.printfn " ViewElement.Create<%s>(ViewBuilders.Create%s, (fun registry prevOpt curr target -> ViewBuilders.Update%s(registry, prevOpt, curr, target)), attribBuilder)" data.FullName data.Name data.Name
w.printfn " ViewElement.Create<%s>(ViewBuilders.Create%s, (fun registry prevOpt curr target -> ViewBuilders.Update%s(registry, prevOpt, curr, target)), attribBuilder, extraAttributes)" data.FullName data.Name data.Name
w.printfn ""


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@
"customAttributeKey": "Fabulous.XamarinForms.ViewExtensions.TagAttribKey",
"defaultValue": "null",
"inputType": "obj"
},
{
"source": null,
"name": "ExtraAttributes",
"canBeUpdated": false,
"defaultValue": "null",
"inputType": "(ViewElement -> ViewElement) list"
}
],
"events": [
Expand Down
46 changes: 39 additions & 7 deletions src/Fabulous/ViewElement.fs
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,12 @@ type AttributeKey<'T> internal (keyv: int) =


/// A description of a visual element
type AttributesBuilder (attribCount: int) =
type AttributesBuilder (attribCount: int, extraCount: int) =

let mutable count = extraCount
let mutable attribs = Array.zeroCreate<KeyValuePair<int, obj>>(attribCount)

let mutable count = 0
let mutable attribs = Array.zeroCreate<KeyValuePair<int, obj>>(attribCount)
new (attribCount) = AttributesBuilder(attribCount, 0)

/// Get the attributes of the visual element
[<DebuggerBrowsable(DebuggerBrowsableState.RootHidden)>]
Expand Down Expand Up @@ -108,9 +110,11 @@ type ViewRef<'T when 'T : not struct>() =
/// A description of a visual element
type ViewElement internal (targetType: Type, create: (unit -> obj), update: (ViewElement voption -> ViewElement -> obj -> unit), attribs: KeyValuePair<int,obj>[]) =

let extraAttribsCounter = ref 0

new (targetType: Type, create: (unit -> obj), update: (ViewElement voption -> ViewElement -> obj -> unit), attribsBuilder: AttributesBuilder) =
ViewElement(targetType, create, update, attribsBuilder.Close())

static member Create
(create: (unit -> 'T),
update: (Dictionary<int, ViewElement voption -> ViewElement -> obj -> unit> -> ViewElement voption -> ViewElement -> 'T -> unit),
Expand All @@ -122,6 +126,24 @@ type ViewElement internal (targetType: Type, create: (unit -> obj), update: (Vie
attribsBuilder.Close()
)

static member Create
(create: (unit -> 'T),
update: (Dictionary<int, ViewElement voption -> ViewElement -> obj -> unit> -> ViewElement voption -> ViewElement -> 'T -> unit),
attribsBuilder: AttributesBuilder,
extraAttributes: (ViewElement -> ViewElement) list option) =
let viewElement =
ViewElement(
typeof<'T>, (create >> box),
(fun prev curr target -> update (Dictionary()) prev curr (unbox target)),
attribsBuilder.Close()
)

match extraAttributes with
| Some extraAttributes when extraAttributes.Length > 0 ->
viewElement.WithExtraAttributes(extraAttributes)
| _ ->
viewElement

static member val CreatedAttribKey : AttributeKey<obj -> unit> = AttributeKey<_>("Created")
static member val RefAttribKey : AttributeKey<ViewRef> = AttributeKey<_>("Ref")
static member val KeyAttribKey : AttributeKey<string> = AttributeKey<_>("Key")
Expand Down Expand Up @@ -180,7 +202,7 @@ type ViewElement internal (targetType: Type, create: (unit -> obj), update: (Vie
target

/// Produce a new visual element with an adjusted attribute
member __.WithAttribute(key: AttributeKey<'T>, value: 'T) =
member x.WithAttribute(key: AttributeKey<'T>, value: 'T) =
let duplicateViewElement newAttribsLength attribIndex =
let attribs2 = Array.zeroCreate newAttribsLength
Array.blit attribs 0 attribs2 0 attribs.Length
Expand All @@ -194,8 +216,18 @@ type ViewElement internal (targetType: Type, create: (unit -> obj), update: (Vie
| Some i ->
duplicateViewElement n i // duplicate and replace existing attribute
| None ->
duplicateViewElement (n + 1) n // duplicate and add new attribute

if attribs.[!extraAttribsCounter] = Unchecked.defaultof<KeyValuePair<_,_>> then
attribs.[!extraAttribsCounter] <- KeyValuePair(key.KeyValue, box value)
incr extraAttribsCounter
x
else
duplicateViewElement (n + 1) n // duplicate and add new attribute

member x.WithExtraAttributes(extraAttributes: (ViewElement -> ViewElement) list) =
if extraAttributes.Length > 0
then extraAttributes |> Seq.map (fun apply -> apply x) |> Seq.last
else x

override x.ToString() = sprintf "%s(...)@%d" x.TargetType.Name (x.GetHashCode())


Expand Down