From 546b9e572fbc680d29c819cda98c9d49e19cb048 Mon Sep 17 00:00:00 2001 From: Carson Katri Date: Wed, 15 Jun 2022 10:34:13 -0400 Subject: [PATCH] Add `_PaddingLayout` support to layout engine (#485) * Initial Reconciler using visitor pattern * Preliminary static HTML renderer using the new reconciler * Add environment * Initial DOM renderer * Nearly-working and simplified reconciler * Working reconciler for HTML/DOM renderers * Rename files, and split code across files * Add some documentation and refinements * Remove GraphRendererTests * Initial layout engine (only implemented for the TestRenderer) * Layout engine for the DOM renderer * Refined layout pass * Revise positioning and restoration of position styles on .update * Re-add Optional.body for StackReconciler-based renderers * Add text measurement * Add spacing to StackLayout * Add benchmarks to compare the stack/fiber reconcilers * Fix some issues created for the StackReconciler, and add update benchmarks * Add BenchmarkState.measure to only calculate the time to update * Fix hang in update shallow benchmark * Fix build errors * Address build issues * Remove File.swift headers * Rename Element -> FiberElement and Element.Data -> FiberElement.Content * Add doc comment explaining unowned usage * Add doc comments explaining implicitly unwrapped optionals * Attempt to use Swift instead of JS for applying mutations * Fix issue with not applying updates to DOMFiberElement * Add comment explaining manual implementation of Hashable for PropertyInfo * Fix linter issues * Remove dynamicMember label from subscript * Re-enable carton test * Attempt GTK fix * Add option to disable layout in the FiberReconciler * Re-enable TokamakDemo with StackReconciler * Restore CI config * Restore CI config * Add file headers and cleanup structure * Add 'px' to font-size in test outputs * Remove extra newlines * Keep track of 'elementChildren' so children are positioned in the correct order * Use a ViewVisitor to pass the correct View type to the proposeSize function * Add support for view modifiers * Add frame modifier to demonstrate modifiers * Fix TestRenderer * Remove unused property * Add PaddingLayoutComputer * Fix doc comment * Fix doc comment * Fix linter issues and refactor slightly * Fix benchmark builds * Attempt to fix benchmarks * Fix sibling layout issues * Restore original demo * Address review comments * Remove maxAxis and fitAxis properties * Use switch instead of ternary operators * Add more documentation to layout steps * Resolve reconciler issue due to alternate child not being cleared/released * Apply suggestions from code review Co-authored-by: Max Desiatov * Reuse Text resolution code. * Add more documentation * Fix typo * Use structs for LayoutComputers * Update AlignmentID demo * Fix weird formatting * Fix copyright year * Restore original demo * Move attribute to newline * Address review comments Co-authored-by: Max Desiatov --- .../Fiber/Layout/PaddingLayoutComputer.swift | 84 +++++++++++++++++++ .../Modifiers/LayoutModifiers.swift | 9 ++ 2 files changed, 93 insertions(+) create mode 100644 Sources/TokamakCore/Fiber/Layout/PaddingLayoutComputer.swift diff --git a/Sources/TokamakCore/Fiber/Layout/PaddingLayoutComputer.swift b/Sources/TokamakCore/Fiber/Layout/PaddingLayoutComputer.swift new file mode 100644 index 000000000..8904e6fb5 --- /dev/null +++ b/Sources/TokamakCore/Fiber/Layout/PaddingLayoutComputer.swift @@ -0,0 +1,84 @@ +// Copyright 2022 Tokamak contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Created by Carson Katri on 5/28/22. +// + +import Foundation + +private extension EdgeInsets { + init(applying edges: Edge.Set, to insets: EdgeInsets) { + self.init( + top: edges.contains(.top) ? insets.top : 0, + leading: edges.contains(.leading) ? insets.leading : 0, + bottom: edges.contains(.bottom) ? insets.bottom : 0, + trailing: edges.contains(.trailing) ? insets.trailing : 0 + ) + } +} + +/// A `LayoutComputer` that fits to its children then adds padding. +struct PaddingLayoutComputer: LayoutComputer { + let proposedSize: CGSize + let insets: EdgeInsets + + init(proposedSize: CGSize, edges: Edge.Set, insets: EdgeInsets?) { + self.proposedSize = proposedSize + self.insets = .init(applying: edges, to: insets ?? EdgeInsets(_all: 10)) + } + + func proposeSize(for child: V, at index: Int, in context: LayoutContext) -> CGSize + where V: View + { + .init( + width: proposedSize.width - insets.leading - insets.trailing, + height: proposedSize.height - insets.top - insets.bottom + ) + } + + func position(_ child: LayoutContext.Child, in context: LayoutContext) -> CGPoint { + .init( + x: insets.leading, + y: insets.top + ) + } + + func requestSize(in context: LayoutContext) -> CGSize { + let childSize = context.children.reduce(CGSize.zero) { + .init( + width: max($0.width, $1.dimensions.width), + height: max($0.height, $1.dimensions.height) + ) + } + return .init( + width: childSize.width + insets.leading + insets.trailing, + height: childSize.height + insets.top + insets.bottom + ) + } +} + +public extension _PaddingLayout { + static func _makeView(_ inputs: ViewInputs) -> ViewOutputs { + .init( + inputs: inputs, + layoutComputer: { + PaddingLayoutComputer( + proposedSize: $0, + edges: inputs.content.edges, + insets: inputs.content.insets + ) + } + ) + } +} diff --git a/Sources/TokamakStaticHTML/Modifiers/LayoutModifiers.swift b/Sources/TokamakStaticHTML/Modifiers/LayoutModifiers.swift index 982f3677d..bc810d8db 100644 --- a/Sources/TokamakStaticHTML/Modifiers/LayoutModifiers.swift +++ b/Sources/TokamakStaticHTML/Modifiers/LayoutModifiers.swift @@ -144,6 +144,15 @@ extension _PaddingLayout: DOMViewModifier { } } +@_spi(TokamakStaticHTML) +extension _PaddingLayout: HTMLConvertible { + public var tag: String { "div" } + public func attributes(useDynamicLayout: Bool) -> [HTMLAttribute: String] { + guard !useDynamicLayout else { return [:] } + return attributes + } +} + extension _ShadowEffect._Resolved: DOMViewModifier { public var attributes: [HTMLAttribute: String] { [