Skip to content

Commit

Permalink
Merge pull request #746 from TimLariviere/fix-grid-coldefs-rowdefs
Browse files Browse the repository at this point in the history
Allow superclass properties to update before inherited ones
  • Loading branch information
TimLariviere authored May 20, 2020
2 parents bcc2728 + 0aa38c8 commit b33a869
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 49 deletions.
4 changes: 3 additions & 1 deletion Fabulous.CodeGen/src/Fabulous.CodeGen/Binder/Binder.fs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ module Binder =
BinderHelpers.bindMembers
bindingsCollection.AttachedProperties
(tryBindAttachedProperty logger containerTypeName assemblyTypeAttachedProperties) })
HasPriority = bindingsTypeProperty.HasPriority |> Option.defaultValue false
IsInherited = false }

/// Try to create a bound event binding from the bindings data only
Expand Down Expand Up @@ -243,7 +244,8 @@ module Binder =
AttachedProperties =
BinderHelpers.bindMembers
cd.AttachedProperties
(tryBindAttachedProperty logger containerTypeName assemblyTypeAttachedProperties) })
(tryBindAttachedProperty logger containerTypeName assemblyTypeAttachedProperties) })
HasPriority = bindingsTypeProperty.HasPriority |> Option.defaultValue false
IsInherited = false }
)

Expand Down
1 change: 1 addition & 0 deletions Fabulous.CodeGen/src/Fabulous.CodeGen/Binder/Models.fs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ module Models =
ConvertModelToValue: string
UpdateCode: string
CollectionData: BoundPropertyCollectionData option
HasPriority: bool
IsInherited: bool }
interface IBoundConstructorMember with
member this.ShortName = this.ShortName
Expand Down
100 changes: 54 additions & 46 deletions Fabulous.CodeGen/src/Fabulous.CodeGen/Generator/CodeGenerator.fs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,54 @@ module CodeGenerator =
w

let generateUpdateFunction (data: UpdateData) (w: StringWriter) =
let generateProperties (properties: UpdateProperty array) =
for p in properties do
let hasApply = not (System.String.IsNullOrWhiteSpace(p.ConvertModelToValue)) || not (System.String.IsNullOrWhiteSpace(p.UpdateCode))
let attributeKey = getAttributeKey p.CustomAttributeKey p.UniqueName

// Check if the property is a collection
match p.CollectionDataElementType with
| Some collectionDataElementType when not hasApply ->
w.printfn " ViewUpdaters.updateCollectionGeneric prev%sOpt curr%sOpt target.%s" p.UniqueName p.UniqueName p.Name
w.printfn " (fun (x: ViewElement) -> x.Create() :?> %s)" collectionDataElementType
w.printfn " (match registry.TryGetValue(%s.KeyValue) with true, func -> func | false, _ -> (fun _ _ _ -> ()))" attributeKey
w.printfn " ViewHelpers.canReuseView"
w.printfn " ViewHelpers.tryGetKey"
w.printfn " ViewUpdaters.updateChild"

| Some _ when hasApply ->
w.printfn " %s prev%sOpt curr%sOpt target" p.UpdateCode p.UniqueName p.UniqueName
w.printfn " (match registry.TryGetValue(%s.KeyValue) with true, func -> func | false, _ -> (fun _ _ _ -> ()))" attributeKey

| _ ->
// If the type is ViewElement, then it's a type from the model
// Issue recursive calls to "Create" and "UpdateIncremental"
if p.ModelType = "ViewElement" && not hasApply then
w.printfn " match prev%sOpt, curr%sOpt with" p.UniqueName p.UniqueName
w.printfn " // For structured objects, dependsOn on reference equality"
w.printfn " | ValueSome prevValue, ValueSome newValue when identical prevValue newValue -> ()"
w.printfn " | ValueSome prevValue, ValueSome newValue when canReuseView prevValue newValue ->"
w.printfn " newValue.UpdateIncremental(prevValue, target.%s)" p.Name
w.printfn " | _, ValueSome newValue ->"
w.printfn " target.%s <- (newValue.Create() :?> %s)" p.Name p.OriginalType
w.printfn " | ValueSome _, ValueNone ->"
w.printfn " target.%s <- null" p.Name
w.printfn " | ValueNone, ValueNone -> ()"

// Explicit update code
elif not (System.String.IsNullOrWhiteSpace(p.UpdateCode)) then
w.printfn " %s prev%sOpt curr%sOpt target" p.UpdateCode p.UniqueName p.UniqueName

else
w.printfn " match prev%sOpt, curr%sOpt with" p.UniqueName p.UniqueName
w.printfn " | ValueSome prevValue, ValueSome currValue when prevValue = currValue -> ()"
w.printfn " | _, ValueSome currValue -> target.%s <- %s currValue" p.Name p.ConvertModelToValue
if p.DefaultValue = "" then
w.printfn " | ValueSome _, ValueNone -> target.ClearValue %s.%sProperty" data.FullName p.Name
else
w.printfn " | ValueSome _, ValueNone -> target.%s <- %s" p.Name p.DefaultValue
w.printfn " | ValueNone, ValueNone -> ()"

w.printfn " static member Update%s (registry: System.Collections.Generic.Dictionary<int, ViewElement voption -> ViewElement -> obj -> unit>, prevOpt: ViewElement voption, curr: ViewElement, target: %s) = " data.Name data.FullName

// Attached properties updaters
Expand Down Expand Up @@ -182,6 +230,11 @@ module CodeGenerator =
w.printfn " | ValueSome prevValue -> target.%s.RemoveHandler(prevValue)" e.Name
w.printfn " | ValueNone -> ()"

// Update priority properties
if data.PriorityProperties.Length > 0 then
w.printfn " // Update priority properties"
generateProperties data.PriorityProperties

// Update inherited members
if data.BaseName.IsSome then
w.printfn " // Update inherited members"
Expand All @@ -190,52 +243,7 @@ module CodeGenerator =
// Update properties
if data.Properties.Length > 0 then
w.printfn " // Update properties"
for p in data.Properties do
let hasApply = not (System.String.IsNullOrWhiteSpace(p.ConvertModelToValue)) || not (System.String.IsNullOrWhiteSpace(p.UpdateCode))
let attributeKey = getAttributeKey p.CustomAttributeKey p.UniqueName

// Check if the property is a collection
match p.CollectionDataElementType with
| Some collectionDataElementType when not hasApply ->
w.printfn " ViewUpdaters.updateCollectionGeneric prev%sOpt curr%sOpt target.%s" p.UniqueName p.UniqueName p.Name
w.printfn " (fun (x: ViewElement) -> x.Create() :?> %s)" collectionDataElementType
w.printfn " (match registry.TryGetValue(%s.KeyValue) with true, func -> func | false, _ -> (fun _ _ _ -> ()))" attributeKey
w.printfn " ViewHelpers.canReuseView"
w.printfn " ViewHelpers.tryGetKey"
w.printfn " ViewUpdaters.updateChild"

| Some _ when hasApply ->
w.printfn " %s prev%sOpt curr%sOpt target" p.UpdateCode p.UniqueName p.UniqueName
w.printfn " (match registry.TryGetValue(%s.KeyValue) with true, func -> func | false, _ -> (fun _ _ _ -> ()))" attributeKey

| _ ->
// If the type is ViewElement, then it's a type from the model
// Issue recursive calls to "Create" and "UpdateIncremental"
if p.ModelType = "ViewElement" && not hasApply then
w.printfn " match prev%sOpt, curr%sOpt with" p.UniqueName p.UniqueName
w.printfn " // For structured objects, dependsOn on reference equality"
w.printfn " | ValueSome prevValue, ValueSome newValue when identical prevValue newValue -> ()"
w.printfn " | ValueSome prevValue, ValueSome newValue when canReuseView prevValue newValue ->"
w.printfn " newValue.UpdateIncremental(prevValue, target.%s)" p.Name
w.printfn " | _, ValueSome newValue ->"
w.printfn " target.%s <- (newValue.Create() :?> %s)" p.Name p.OriginalType
w.printfn " | ValueSome _, ValueNone ->"
w.printfn " target.%s <- null" p.Name
w.printfn " | ValueNone, ValueNone -> ()"

// Explicit update code
elif not (System.String.IsNullOrWhiteSpace(p.UpdateCode)) then
w.printfn " %s prev%sOpt curr%sOpt target" p.UpdateCode p.UniqueName p.UniqueName

else
w.printfn " match prev%sOpt, curr%sOpt with" p.UniqueName p.UniqueName
w.printfn " | ValueSome prevValue, ValueSome currValue when prevValue = currValue -> ()"
w.printfn " | _, ValueSome currValue -> target.%s <- %s currValue" p.Name p.ConvertModelToValue
if p.DefaultValue = "" then
w.printfn " | ValueSome _, ValueNone -> target.ClearValue %s.%sProperty" data.FullName p.Name
else
w.printfn " | ValueSome _, ValueNone -> target.%s <- %s" p.Name p.DefaultValue
w.printfn " | ValueNone, ValueNone -> ()"
generateProperties data.Properties

// Subscribe event handlers
if data.Events.Length > 0 then
Expand Down
1 change: 1 addition & 0 deletions Fabulous.CodeGen/src/Fabulous.CodeGen/Generator/Models.fs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ module Models =
ImmediateMembers : UpdateMember array
Events: UpdateEvent array
Properties: UpdateProperty array
PriorityProperties: UpdateProperty array
PropertiesWithAttachedProperties: UpdatePropertyWithAttachedProperties array }

type ConstructData =
Expand Down
16 changes: 16 additions & 0 deletions Fabulous.CodeGen/src/Fabulous.CodeGen/Generator/Preparer.fs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,21 @@ module Preparer =

let updateProperties =
immediateProperties
|> Array.filter (fun p -> not p.HasPriority)
|> Array.map (fun p ->
{ Name = p.Name
UniqueName = p.UniqueName
CustomAttributeKey = p.CustomAttributeKey
DefaultValue = p.DefaultValue
OriginalType = p.OriginalType
ModelType = p.ModelType
ConvertModelToValue = p.ConvertModelToValue
UpdateCode = p.UpdateCode
CollectionDataElementType = p.CollectionData |> Option.map (fun c -> c.ElementType) })

let updatePriorityProperties =
immediateProperties
|> Array.filter (fun p -> p.HasPriority)
|> Array.map (fun p ->
{ Name = p.Name
UniqueName = p.UniqueName
Expand Down Expand Up @@ -107,6 +122,7 @@ module Preparer =
ImmediateMembers = immediateMembers
Events = updateEvents
Properties = updateProperties
PriorityProperties = updatePriorityProperties
PropertiesWithAttachedProperties = updatePropertiesWithAttachedProperties }

let toConstructData (boundType: BoundType) : ConstructData =
Expand Down
1 change: 1 addition & 0 deletions Fabulous.CodeGen/src/Fabulous.CodeGen/Models.fs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ module Models =
member val DefaultValue = None with get, set
member val ConvertModelToValue = None with get, set
member val UpdateCode = None with get, set
member val HasPriority : bool option = None with get, set

interface IConstructorMember with
member x.ShortName = x.ShortName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2083,7 +2083,8 @@
"shortName": "coldefs",
"inputType": "Fabulous.XamarinForms.InputTypes.Dimension list",
"defaultValue": "Xamarin.Forms.ColumnDefinitionCollection()",
"convertModelToValue": "ViewConverters.convertFabulousDimensionToXamarinFormsColumnDefinition"
"convertModelToValue": "ViewConverters.convertFabulousDimensionToXamarinFormsColumnDefinition",
"hasPriority": true
},
{
"source": "ColumnSpacing"
Expand All @@ -2093,7 +2094,8 @@
"shortName": "rowdefs",
"inputType": "Fabulous.XamarinForms.InputTypes.Dimension list",
"defaultValue": "Xamarin.Forms.RowDefinitionCollection()",
"convertModelToValue": "ViewConverters.convertFabulousDimensionToXamarinFormsRowDefinition"
"convertModelToValue": "ViewConverters.convertFabulousDimensionToXamarinFormsRowDefinition",
"hasPriority": true
},
{
"source": "RowSpacing"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ module XFOptimizerTests =
ConvertModelToValue = ""
UpdateCode = ""
CollectionData = None
HasPriority = false
IsInherited = false } |]

let expectedBoundModel =
Expand All @@ -59,6 +60,7 @@ module XFOptimizerTests =
ConvertModelToValue = ""
UpdateCode = "(fun _ _ _ -> ())"
CollectionData = None
HasPriority = false
IsInherited = false }

{ Name = "NameCanExecute"
Expand All @@ -74,6 +76,7 @@ module XFOptimizerTests =
ConvertModelToValue = ""
UpdateCode = "ViewUpdaters.updateCommand prevUniqueNameOpt currUniqueNameOpt (fun _target -> ()) (fun (target: FullName) cmd -> target.Name <- cmd)"
CollectionData = None
HasPriority = false
IsInherited = false } |]

boundModel |> OptimizeCommands.apply |> should equal expectedBoundModel
Expand All @@ -95,6 +98,7 @@ module XFOptimizerTests =
ConvertModelToValue = ""
UpdateCode = ""
CollectionData = None
HasPriority = false
IsInherited = false } |]

let expectedBoundModel = boundModel
Expand All @@ -118,6 +122,7 @@ module XFOptimizerTests =
ConvertModelToValue = ""
UpdateCode = "ViewUpdaters.updateNameProperty"
CollectionData = None
HasPriority = false
IsInherited = false } |]

let expectedBoundModel = boundModel
Expand All @@ -141,6 +146,7 @@ module XFOptimizerTests =
ConvertModelToValue = ""
UpdateCode = ""
CollectionData = None
HasPriority = false
IsInherited = false } |]

let expectedBoundModel = boundModel
Expand All @@ -164,6 +170,7 @@ module XFOptimizerTests =
ConvertModelToValue = ""
UpdateCode = ""
CollectionData = None
HasPriority = false
IsInherited = false } |]

let expectedBoundModel =
Expand All @@ -181,6 +188,7 @@ module XFOptimizerTests =
ConvertModelToValue = "ViewConverters.convertFabulousImageToXamarinFormsImageSource"
UpdateCode = ""
CollectionData = None
HasPriority = false
IsInherited = false } |]

boundModel |> OptimizeImageSource.apply |> should equal expectedBoundModel
Expand All @@ -202,6 +210,7 @@ module XFOptimizerTests =
ConvertModelToValue = ""
UpdateCode = ""
CollectionData = None
HasPriority = false
IsInherited = false } |]

let expectedBoundModel = boundModel
Expand All @@ -225,6 +234,7 @@ module XFOptimizerTests =
ConvertModelToValue = ""
UpdateCode = "ViewUpdaters.updateNameProperty"
CollectionData = None
HasPriority = false
IsInherited = false } |]

let expectedBoundModel = boundModel
Expand All @@ -248,6 +258,7 @@ module XFOptimizerTests =
ConvertModelToValue = ""
UpdateCode = ""
CollectionData = None
HasPriority = false
IsInherited = false } |]

let expectedBoundModel = boundModel
Expand All @@ -271,6 +282,7 @@ module XFOptimizerTests =
ConvertModelToValue = ""
UpdateCode = ""
CollectionData = None
HasPriority = false
IsInherited = false } |]

let expectedBoundModel =
Expand All @@ -288,6 +300,7 @@ module XFOptimizerTests =
ConvertModelToValue = "ViewConverters.convertFabulousMediaToXamarinFormsMediaSource"
UpdateCode = ""
CollectionData = None
HasPriority = false
IsInherited = false } |]

boundModel |> OptimizeMediaSource.apply |> should equal expectedBoundModel
Expand All @@ -309,6 +322,7 @@ module XFOptimizerTests =
ConvertModelToValue = ""
UpdateCode = ""
CollectionData = None
HasPriority = false
IsInherited = false } |]

let expectedBoundModel = boundModel
Expand All @@ -332,6 +346,7 @@ module XFOptimizerTests =
ConvertModelToValue = ""
UpdateCode = "ViewUpdaters.updateNameProperty"
CollectionData = None
HasPriority = false
IsInherited = false } |]

let expectedBoundModel = boundModel
Expand All @@ -355,6 +370,7 @@ module XFOptimizerTests =
ConvertModelToValue = ""
UpdateCode = ""
CollectionData = None
HasPriority = false
IsInherited = false } |]

let expectedBoundModel = boundModel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ module XFOptimizer =
ConvertModelToValue = ""
UpdateCode = sprintf "ViewUpdaters.updateCommand prev%sOpt curr%sOpt (fun _target -> ()) (fun (target: %s) cmd -> target.%s <- cmd)" boundProperty.UniqueName boundProperty.UniqueName boundType.FullName boundProperty.Name
CollectionData = None
HasPriority = false
IsInherited = false }
|]

Expand Down

0 comments on commit b33a869

Please sign in to comment.