99import UIKit
1010
1111final class LayoutEngine {
12- private let spreadsheetView : SpreadsheetView
13- private let scrollView : ScrollView
12+ struct Layouter : ViewLayouter {
13+ let scrollView : ScrollView
1414
15- private let intercellSpacing : CGSize
16- private let defaultGridStyle : GridStyle
17- private let circularScrollingOptions : CircularScrolling . Configuration . Options
18- private let blankCellReuseIdentifier : String
19- private let highlightedIndexPaths : Set < IndexPath >
20- private let selectedIndexPaths : Set < IndexPath >
15+ func layout( cell: Cell ) {
16+ scrollView. insertSubview ( cell, at: 0 )
17+ }
18+ }
19+ var layouter : ViewLayouter
2120
22- private let frozenColumns : Int
23- private let frozenRows : Int
21+ private let spreadsheetView : SpreadsheetView
22+ private let scrollView : ScrollView
2423
25- private let columnWidthCache : [ CGFloat ]
26- private let rowHeightCache : [ CGFloat ]
24+ private let spreadsheetViewConfiguration : SpreadsheetViewConfiguration
25+ private let dataSourceSnapshot : DataSourceSnapshot
26+ private let scrollViewConfiguration : ScrollViewConfiguration
2727
2828 private let visibleRect : CGRect
2929 private var cellOrigin : CGPoint
3030
31- private let startColumn : Int
32- private let startRow : Int
33- private let numberOfColumns : Int
34- private let numberOfRows : Int
35- private let columnCount : Int
36- private let rowCount : Int
37- private let insets : CGPoint
38-
39- private let columnRecords : [ CGFloat ]
40- private let rowRecords : [ CGFloat ]
41-
4231 private var mergedCellAddresses = Set < Address > ( )
4332 private var mergedCellRects = [ Address: CGRect] ( )
4433
@@ -54,41 +43,133 @@ final class LayoutEngine {
5443 init ( spreadsheetView: SpreadsheetView , scrollView: ScrollView ) {
5544 self . spreadsheetView = spreadsheetView
5645 self . scrollView = scrollView
46+ self . layouter = Layouter ( scrollView: scrollView)
47+
48+ spreadsheetViewConfiguration = SpreadsheetViewConfiguration ( intercellSpacing: spreadsheetView. intercellSpacing,
49+ defaultGridStyle: spreadsheetView. gridStyle,
50+ circularScrollingOptions: spreadsheetView. circularScrollingOptions,
51+ circularScrollScalingFactor: spreadsheetView. circularScrollScalingFactor,
52+ blankCellReuseIdentifier: spreadsheetView. blankCellReuseIdentifier,
53+ highlightedIndexPaths: spreadsheetView. highlightedIndexPaths,
54+ selectedIndexPaths: spreadsheetView. selectedIndexPaths)
55+ dataSourceSnapshot = DataSourceSnapshot ( frozenColumns: spreadsheetView. layoutProperties. frozenColumns, frozenRows: spreadsheetView. layoutProperties. frozenRows,
56+ columnWidthCache: spreadsheetView. layoutProperties. columnWidthCache, rowHeightCache: spreadsheetView. layoutProperties. rowHeightCache)
57+
58+ scrollViewConfiguration = ScrollViewConfiguration ( startColumn: scrollView. layoutAttributes. startColumn, startRow: scrollView. layoutAttributes. startRow,
59+ numberOfColumns: scrollView. layoutAttributes. numberOfColumns, numberOfRows: scrollView. layoutAttributes. numberOfRows,
60+ columnCount: scrollView. layoutAttributes. columnCount, rowCount: scrollView. layoutAttributes. rowCount,
61+ insets: scrollView. layoutAttributes. insets,
62+ columnRecords: scrollView. columnRecords, rowRecords: scrollView. rowRecords)
63+
64+ visibleRect = CGRect ( origin: scrollView. state. contentOffset, size: scrollView. state. frame. size)
65+ cellOrigin = . zero
66+ }
5767
58- intercellSpacing = spreadsheetView. intercellSpacing
59- defaultGridStyle = spreadsheetView. gridStyle
60- circularScrollingOptions = spreadsheetView. circularScrollingOptions
61- blankCellReuseIdentifier = spreadsheetView. blankCellReuseIdentifier
62- highlightedIndexPaths = spreadsheetView. highlightedIndexPaths
63- selectedIndexPaths = spreadsheetView. selectedIndexPaths
68+ init ( spreadsheetViewConfiguration: SpreadsheetViewConfiguration , dataSourceSnapshot: DataSourceSnapshot , scrollViewConfiguration: ScrollViewConfiguration , scrollViewState: ScrollView . State ) {
69+ class DataSource : SpreadsheetViewDataSource {
70+ func numberOfColumns( in spreadsheetView: SpreadsheetView ) -> Int {
71+ return 0
72+ }
6473
65- frozenColumns = spreadsheetView. layoutProperties. frozenColumns
66- frozenRows = spreadsheetView. layoutProperties. frozenRows
67- columnWidthCache = spreadsheetView. layoutProperties. columnWidthCache
68- rowHeightCache = spreadsheetView. layoutProperties. rowHeightCache
74+ func numberOfRows( in spreadsheetView: SpreadsheetView ) -> Int {
75+ return 0
76+ }
6977
70- visibleRect = CGRect ( origin: scrollView. state. contentOffset, size: scrollView. state. frame. size)
71- cellOrigin = CGPoint . zero
72-
73- startColumn = scrollView. layoutAttributes. startColumn
74- startRow = scrollView. layoutAttributes. startRow
75- numberOfColumns = scrollView. layoutAttributes. numberOfColumns
76- numberOfRows = scrollView. layoutAttributes. numberOfRows
77- columnCount = scrollView. layoutAttributes. columnCount
78- rowCount = scrollView. layoutAttributes. rowCount
79- insets = scrollView. layoutAttributes. insets
80-
81- columnRecords = scrollView. columnRecords
82- rowRecords = scrollView. rowRecords
78+ func spreadsheetView( _ spreadsheetView: SpreadsheetView , widthForColumn column: Int ) -> CGFloat {
79+ return 0
80+ }
81+
82+ func spreadsheetView( _ spreadsheetView: SpreadsheetView , heightForRow column: Int ) -> CGFloat {
83+ return 0
84+ }
85+ }
86+ spreadsheetView = SpreadsheetView ( )
87+ scrollView = ScrollView ( )
88+ struct CellInfo {
89+ let frame : CGRect
90+ let indexPath : IndexPath
91+ }
92+
93+ struct DebugLayouter : ViewLayouter , CustomStringConvertible {
94+ let dataSource = DataSource ( )
95+ var cells = [ CellInfo] ( )
96+
97+ mutating func layout( cell: Cell ) {
98+ cells. append ( CellInfo ( frame: cell. frame, indexPath: cell. indexPath) )
99+ }
100+
101+ var description : String {
102+ let sortedCells = cells. sorted { ( lhs, rhs) -> Bool in
103+ if lhs. indexPath. row < rhs. indexPath. row {
104+ return true
105+ }
106+ if lhs. indexPath. row > rhs. indexPath. row {
107+ return false
108+ }
109+ return lhs. indexPath. column < rhs. indexPath. column
110+ }
111+ var string = " "
112+ var previousRow = 0
113+ if sortedCells. count > 0 {
114+ previousRow = sortedCells [ 0 ] . indexPath. row
115+ }
116+ for cell in sortedCells {
117+ let indexPath = cell. indexPath
118+ if previousRow != indexPath. row {
119+ string += " | \n "
120+ previousRow = indexPath. row
121+ }
122+ string += " | "
123+ let location = " R \( indexPath. row) C \( indexPath. column) "
124+ string += String ( repeating: " " , count: 6 - location. characters. count)
125+ string += location
126+ let frame = " \( cell. frame) "
127+ string += String ( repeating: " " , count: 27 - frame. characters. count)
128+ string += frame
129+ }
130+ string += " | \n "
131+ return string
132+ }
133+ }
134+ let debugLayouter = DebugLayouter ( )
135+ layouter = debugLayouter
136+ spreadsheetView. dataSource = debugLayouter. dataSource
137+
138+ self . spreadsheetViewConfiguration = SpreadsheetViewConfiguration ( intercellSpacing: spreadsheetViewConfiguration. intercellSpacing,
139+ defaultGridStyle: spreadsheetViewConfiguration. defaultGridStyle,
140+ circularScrollingOptions: spreadsheetViewConfiguration. circularScrollingOptions,
141+ circularScrollScalingFactor: spreadsheetView. circularScrollScalingFactor,
142+ blankCellReuseIdentifier: spreadsheetView. blankCellReuseIdentifier,
143+ highlightedIndexPaths: spreadsheetViewConfiguration. highlightedIndexPaths,
144+ selectedIndexPaths: spreadsheetViewConfiguration. selectedIndexPaths)
145+ self . dataSourceSnapshot = dataSourceSnapshot
146+ self . scrollViewConfiguration = scrollViewConfiguration
147+
148+ visibleRect = CGRect ( origin: scrollViewState. contentOffset, size: scrollViewState. frame. size)
149+ cellOrigin = . zero
83150 }
84151
85152 func layout( ) {
153+ let startColumn = scrollViewConfiguration. startColumn
154+ let startRow = scrollViewConfiguration. startRow
155+ let numberOfRows = scrollViewConfiguration. numberOfRows
156+ let columnCount = scrollViewConfiguration. columnCount
157+ let rowCount = scrollViewConfiguration. rowCount
158+ let insets = scrollViewConfiguration. insets
159+
160+ let rowRecords = scrollViewConfiguration. rowRecords
161+
86162 guard startColumn != columnCount && startRow != rowCount else {
87163 return
88164 }
89165
90- let startRowIndex = spreadsheetView. findIndex ( in: scrollView. rowRecords, for: visibleRect. origin. y - insets. y)
91- cellOrigin. y = insets. y + scrollView. rowRecords [ startRowIndex] + intercellSpacing. height
166+ let intercellSpacing = spreadsheetViewConfiguration. intercellSpacing
167+ let circularScrollingOptions = spreadsheetViewConfiguration. circularScrollingOptions
168+ let frozenRows = dataSourceSnapshot. frozenRows
169+ let rowHeightCache = dataSourceSnapshot. rowHeightCache
170+
171+ let startRowIndex = spreadsheetView. findIndex ( in: rowRecords, for: visibleRect. origin. y - insets. y)
172+ cellOrigin. y = insets. y + rowRecords[ startRowIndex] + intercellSpacing. height
92173
93174 for rowIndex in ( startRowIndex + startRow) ..< rowCount {
94175 let row = rowIndex % numberOfRows
@@ -111,6 +192,20 @@ final class LayoutEngine {
111192 }
112193
113194 private func enumerateColumns( currentRow row: Int , currentRowIndex rowIndex: Int ) -> Bool {
195+ let intercellSpacing = spreadsheetViewConfiguration. intercellSpacing
196+ let circularScrollingOptions = spreadsheetViewConfiguration. circularScrollingOptions
197+ let frozenColumns = dataSourceSnapshot. frozenColumns
198+ let columnWidthCache = dataSourceSnapshot. columnWidthCache
199+ let rowHeightCache = dataSourceSnapshot. rowHeightCache
200+
201+ let startColumn = scrollViewConfiguration. startColumn
202+ let startRow = scrollViewConfiguration. startRow
203+ let numberOfColumns = scrollViewConfiguration. numberOfColumns
204+ let columnCount = scrollViewConfiguration. columnCount
205+ let insets = scrollViewConfiguration. insets
206+ let columnRecords = scrollViewConfiguration. columnRecords
207+ let rowRecords = scrollViewConfiguration. rowRecords
208+
114209 let startColumnIndex = spreadsheetView. findIndex ( in: columnRecords, for: visibleRect. origin. x - insets. x)
115210 cellOrigin. x = insets. x + columnRecords[ startColumnIndex] + intercellSpacing. width
116211
@@ -264,6 +359,10 @@ final class LayoutEngine {
264359 return
265360 }
266361
362+ let blankCellReuseIdentifier = spreadsheetViewConfiguration. blankCellReuseIdentifier
363+ let highlightedIndexPaths = spreadsheetViewConfiguration. highlightedIndexPaths
364+ let selectedIndexPaths = spreadsheetViewConfiguration. selectedIndexPaths
365+
267366 let gridlines : Gridlines ?
268367 let border : ( borders: Borders ? , hasBorders: Bool )
269368
@@ -291,7 +390,7 @@ final class LayoutEngine {
291390 gridlines = cell. gridlines
292391 border = ( cell. borders, cell. hasBorder)
293392
294- scrollView . insertSubview ( cell, at : 0 )
393+ layouter . layout ( cell: cell )
295394 scrollView. visibleCells [ address] = cell
296395 }
297396
@@ -350,6 +449,8 @@ final class LayoutEngine {
350449 }
351450
352451 private func renderHorizontalGridlines( ) {
452+ let intercellSpacing = spreadsheetViewConfiguration. intercellSpacing
453+
353454 for (address, gridLayout) in horizontalGridLayouts {
354455 var frame = CGRect . zero
355456 frame. origin = gridLayout. origin
@@ -385,6 +486,8 @@ final class LayoutEngine {
385486 }
386487
387488 private func renderVerticalGridlines( ) {
489+ let intercellSpacing = spreadsheetViewConfiguration. intercellSpacing
490+
388491 for (address, gridLayout) in verticalGridLayouts {
389492 var frame = CGRect . zero
390493 frame. origin = gridLayout. origin
@@ -440,6 +543,8 @@ final class LayoutEngine {
440543 }
441544
442545 private func extractGridStyle( style: GridStyle ) -> ( width: CGFloat , color: UIColor , priority: CGFloat ) {
546+ let defaultGridStyle = spreadsheetViewConfiguration. defaultGridStyle
547+
443548 let gridWidth : CGFloat
444549 let gridColor : UIColor
445550 let priority : CGFloat
@@ -512,6 +617,35 @@ final class LayoutEngine {
512617 }
513618}
514619
620+ struct SpreadsheetViewConfiguration {
621+ let intercellSpacing : CGSize
622+ let defaultGridStyle : GridStyle
623+ let circularScrollingOptions : CircularScrolling . Configuration . Options
624+ var circularScrollScalingFactor : ( horizontal: Int , vertical: Int )
625+ let blankCellReuseIdentifier : String
626+ let highlightedIndexPaths : Set < IndexPath >
627+ let selectedIndexPaths : Set < IndexPath >
628+ }
629+
630+ struct DataSourceSnapshot {
631+ let frozenColumns : Int
632+ let frozenRows : Int
633+ let columnWidthCache : [ CGFloat ]
634+ let rowHeightCache : [ CGFloat ]
635+ }
636+
637+ struct ScrollViewConfiguration {
638+ let startColumn : Int
639+ let startRow : Int
640+ let numberOfColumns : Int
641+ let numberOfRows : Int
642+ let columnCount : Int
643+ let rowCount : Int
644+ let insets : CGPoint
645+ let columnRecords : [ CGFloat ]
646+ let rowRecords : [ CGFloat ]
647+ }
648+
515649struct LayoutProperties {
516650 let numberOfColumns : Int
517651 let numberOfRows : Int
@@ -574,3 +708,7 @@ struct GridLayout {
574708 let edge : RectEdge
575709 let priority : CGFloat
576710}
711+
712+ protocol ViewLayouter {
713+ mutating func layout( cell: Cell )
714+ }
0 commit comments