-
-
Notifications
You must be signed in to change notification settings - Fork 111
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Custom Layout Engine for Fiber Reconciler (#472)
* 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 * 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 <[email protected]> * Reuse Text resolution code. * Add more documentation * Fix typo * Use structs for LayoutComputers * Update AlignmentID demo * Fix weird formatting Co-authored-by: Max Desiatov <[email protected]>
- Loading branch information
1 parent
355c880
commit 03513dd
Showing
50 changed files
with
1,416 additions
and
302 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
// 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 2/18/22. | ||
// | ||
|
||
import Foundation | ||
|
||
/// Used to identify an alignment guide. | ||
/// | ||
/// Typically, you would define an alignment guide inside | ||
/// an extension on `HorizontalAlignment` or `VerticalAlignment`: | ||
/// | ||
/// extension HorizontalAlignment { | ||
/// private enum MyAlignmentGuide: AlignmentID { | ||
/// static func defaultValue(in context: ViewDimensions) -> CGFloat { | ||
/// return 0.0 | ||
/// } | ||
/// } | ||
/// public static let myAlignmentGuide = Self(MyAlignmentGuide.self) | ||
/// } | ||
/// | ||
/// Which you can then use with the `alignmentGuide` modifier: | ||
/// | ||
/// VStack(alignment: .myAlignmentGuide) { | ||
/// Text("Align Leading") | ||
/// .border(.red) | ||
/// .alignmentGuide(.myAlignmentGuide) { $0[.leading] } | ||
/// Text("Align Trailing") | ||
/// .border(.blue) | ||
/// .alignmentGuide(.myAlignmentGuide) { $0[.trailing] } | ||
/// } | ||
/// .border(.green) | ||
public protocol AlignmentID { | ||
/// The default value for this alignment guide | ||
/// when not set via the `alignmentGuide` modifier. | ||
static func defaultValue(in context: ViewDimensions) -> CGFloat | ||
} | ||
|
||
/// An alignment position along the horizontal axis. | ||
@frozen public struct HorizontalAlignment: Equatable { | ||
public static func == (lhs: Self, rhs: Self) -> Bool { | ||
lhs.id == rhs.id | ||
} | ||
|
||
let id: AlignmentID.Type | ||
|
||
public init(_ id: AlignmentID.Type) { | ||
self.id = id | ||
} | ||
} | ||
|
||
extension HorizontalAlignment { | ||
public static let leading = Self(Leading.self) | ||
|
||
private enum Leading: AlignmentID { | ||
static func defaultValue(in context: ViewDimensions) -> CGFloat { | ||
0 | ||
} | ||
} | ||
|
||
public static let center = Self(Center.self) | ||
|
||
private enum Center: AlignmentID { | ||
static func defaultValue(in context: ViewDimensions) -> CGFloat { | ||
context.width / 2 | ||
} | ||
} | ||
|
||
public static let trailing = Self(Trailing.self) | ||
|
||
private enum Trailing: AlignmentID { | ||
static func defaultValue(in context: ViewDimensions) -> CGFloat { | ||
context.width | ||
} | ||
} | ||
} | ||
|
||
@frozen public struct VerticalAlignment: Equatable { | ||
public static func == (lhs: Self, rhs: Self) -> Bool { | ||
lhs.id == rhs.id | ||
} | ||
|
||
let id: AlignmentID.Type | ||
|
||
public init(_ id: AlignmentID.Type) { | ||
self.id = id | ||
} | ||
} | ||
|
||
extension VerticalAlignment { | ||
public static let top = Self(Top.self) | ||
private enum Top: AlignmentID { | ||
static func defaultValue(in context: ViewDimensions) -> CGFloat { | ||
0 | ||
} | ||
} | ||
|
||
public static let center = Self(Center.self) | ||
private enum Center: AlignmentID { | ||
static func defaultValue(in context: ViewDimensions) -> CGFloat { | ||
context.height / 2 | ||
} | ||
} | ||
|
||
public static let bottom = Self(Bottom.self) | ||
private enum Bottom: AlignmentID { | ||
static func defaultValue(in context: ViewDimensions) -> CGFloat { | ||
context.height | ||
} | ||
} | ||
|
||
// TODO: Add baseline vertical alignment guides. | ||
// public static let firstTextBaseline: VerticalAlignment | ||
// public static let lastTextBaseline: VerticalAlignment | ||
} | ||
|
||
/// An alignment in both axes. | ||
public struct Alignment: Equatable { | ||
public var horizontal: HorizontalAlignment | ||
public var vertical: VerticalAlignment | ||
|
||
public init( | ||
horizontal: HorizontalAlignment, | ||
vertical: VerticalAlignment | ||
) { | ||
self.horizontal = horizontal | ||
self.vertical = vertical | ||
} | ||
|
||
public static let topLeading = Self(horizontal: .leading, vertical: .top) | ||
public static let top = Self(horizontal: .center, vertical: .top) | ||
public static let topTrailing = Self(horizontal: .trailing, vertical: .top) | ||
public static let leading = Self(horizontal: .leading, vertical: .center) | ||
public static let center = Self(horizontal: .center, vertical: .center) | ||
public static let trailing = Self(horizontal: .trailing, vertical: .center) | ||
public static let bottomLeading = Self(horizontal: .leading, vertical: .bottom) | ||
public static let bottom = Self(horizontal: .center, vertical: .bottom) | ||
public static let bottomTrailing = Self(horizontal: .trailing, vertical: .bottom) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.