1
1
/*
2
2
Scenes provides a Swift object library with support for renderable entities,
3
3
layers, and scenes. Scenes runs on top of IGIS.
4
- Copyright (C) 2020 Tango Golf Digital, LLC
4
+ Copyright (C) 2020-2021 Tango Golf Digital, LLC
5
5
This program is free software: you can redistribute it and/or modify
6
6
it under the terms of the GNU General Public License as published by
7
7
the Free Software Foundation, either version 3 of the License, or
@@ -28,90 +28,108 @@ import Igis
28
28
/// 5. Containers will resize and reposition their contained entities and
29
29
/// maintaining the *currentCalculatedSize* as the minimum size
30
30
open class ContainableRenderableEntity : RenderableEntity {
31
- /// The owning container, if any
32
- /// This is set when this entity is inserted into a container
33
- public internal( set) weak var owningContainer : RenderableEntityContainer ?
34
-
35
- // ********************************************************************************
36
- // API FOLLOWS
37
- // These functions should be over-ridden by descendant classes
38
- // ********************************************************************************
31
+ /// The owning container, if any.
32
+ /// This is set when this entity is inserted into a container.
33
+ public internal( set) weak var owningContainer : RenderableEntityContainer ?
34
+
35
+ /// Creates a new `ContainableRenderableEntity` from the given paramenters:
36
+ /// - Parameters:
37
+ /// - name: The unique name of the renderable entity. While it's
38
+ /// very useful for debugging purposes to provide a
39
+ /// meaningful name, it's not required.
40
+ /// - topLeft: The topLeft corner point for the entity.
41
+ /// - fixedSize: The size of this entity. If nil, the size will be
42
+ /// calculated.
43
+ public init ( name: String ? = nil ,
44
+ topLeft: Point = Point . zero, fixedSize: Size ? ) {
45
+ self . owningContainer = nil
46
+ self . topLeft = topLeft
47
+ self . _currentCalculatedSize = fixedSize
48
+ self . fixedSize = fixedSize
49
+ self . previousCalculatedSize = nil
39
50
40
- /// Invoked to inform an entity that its size has changed.
41
- /// Descendant classes should only note this change and take action
42
- /// later in *calculate()*.
43
- /// The potential change in size may be due to a new, external size or a new
44
- /// calculated size, either of which MAY result in an actual change in rendered
45
- /// size.
46
- open func sizeChanged( ) {
51
+ super. init ( name: name)
47
52
}
48
53
49
- /// Invoked to inform an entity that its *topLeft* has changed.
50
- /// Descendant classes should only note this change and take action
51
- /// later in *calculate()*.
52
- open func topLeftChanged( ) {
54
+ // *****************************************************************
55
+ // Functions for internal use
56
+ // *****************************************************************
57
+
58
+ // sets the *currentCalculatedSize*.
59
+ internal func setCurrentCalculatedSize( ) {
60
+ currentCalculatedSize = calculateSize ( )
53
61
}
54
62
55
-
56
- // ********************************************************************************
63
+ // ****************************************************************
57
64
// API FOLLOWS
58
- // ********************************************************************************
65
+ // ****************************************************************
59
66
60
67
/// The topLeft point of the entity
61
68
/// When set, this entity must reposition accordingly.
62
69
public var topLeft : Point {
63
70
didSet {
64
- topLeftChanged ( )
71
+ if oldValue != topLeft {
72
+ topLeftChanged ( )
73
+ }
65
74
}
66
75
}
67
76
68
77
/// The externally specified size of the entity, overriding
69
78
/// the *currentCalculatedSize*.
70
79
public var externalSize : Size ? {
71
80
didSet {
72
- sizeChanged ( )
81
+ if oldValue != externalSize {
82
+ sizeChanged ( )
83
+ }
73
84
}
74
85
}
75
86
76
- /// The **internally** calculated size of the entity.
77
- /// nil if the size is not currently available.
87
+ /// Used for the *currentCaclulcatedSize* if specified.
88
+ /// If specifed, the *currentCalculatedSize* cannot be changed.
89
+ public let fixedSize : Size ?
90
+
91
+ /// The previously calculated size, set to the *currentCalculatedSize* whenever
92
+ /// that value is about to change to a non-nil value.
93
+ /// This is important for stand-alone `ContainableRenderableEntity`s because
94
+ /// they never have an *externalSize* so they'd temporarily lose their size
95
+ /// during a recalculation.
96
+ public private( set) var previousCalculatedSize : Size ?
97
+
98
+ // stores *currentCalculatedSize* internally.
99
+ private var _currentCalculatedSize : Size ?
78
100
/// Descendant classes must set this value to nil when it is necessary to
79
101
/// recalculate the entity's size.
80
- /// The descendant class should observe that *currentCalculatedSize* is nil
81
- /// in its *calculate()* method, and perform the required operations
82
- /// to calculate and set the new size.
83
- private var _currentCalculatedSize : Size ?
102
+ /// They will then be asked to recalculate their size
103
+ /// in the *calculatedRect()* method.
84
104
public var currentCalculatedSize : Size ? {
85
105
get {
86
106
return _currentCalculatedSize
87
107
}
88
108
set {
89
- // Only if the fixedSize is not nil do we allow changes
90
- if fixedSize == nil {
91
- /// Preserve the current value (but don't overwrite the previous value with nil)
92
- if _currentCalculatedSize != nil {
93
- previousCalculatedSize = _currentCalculatedSize
94
- }
95
-
96
- /// Set the newValue
109
+ // Only if fixedSize is nil do we allow changes
110
+ guard fixedSize == nil else {
111
+ return
112
+ }
113
+
114
+ // Preserve the current value (but don't overwrite the previous value with nil)
115
+ if _currentCalculatedSize != nil {
116
+ previousCalculatedSize = _currentCalculatedSize
117
+ }
118
+
119
+ // if the newValue is different, set to currentCalculated size and notify
120
+ // owning container
121
+ if newValue != _currentCalculatedSize {
97
122
_currentCalculatedSize = newValue
98
-
99
- /// Notify our owning container
100
- if let owningContainer = owningContainer {
101
- owningContainer. childDidSetCurrentCalculatedSize ( child: self , newSize: newValue)
123
+ owningContainer? . currentCalculatedSize = nil
124
+
125
+ // if external size is nil, notify entity that size has changed
126
+ if externalSize == nil {
127
+ sizeChanged ( )
102
128
}
103
- }
104
- sizeChanged ( )
129
+ }
105
130
}
106
131
}
107
132
108
- /// The previously calculated size, set to the *currentCalculatedSize* whenever
109
- /// that value is about to change to a non-nil value
110
- /// This is important for stand-alone `ContainableRenderableEntity`s because
111
- /// they never have an *externalSize* so they'd temporarily lose their size
112
- /// during a recalculation.
113
- public private( set) var previousCalculatedSize : Size ?
114
-
115
133
/// The most recently available calculated size
116
134
public var mostRecentCalculatedSize : Size ? {
117
135
return currentCalculatedSize ?? previousCalculatedSize
@@ -123,21 +141,63 @@ open class ContainableRenderableEntity : RenderableEntity {
123
141
return externalSize ?? mostRecentCalculatedSize
124
142
}
125
143
126
- /// Used for the *currentCaclulcatedSize* if specified
127
- /// If specifed, the *currentCalculatedSize* cannot be changed
128
- public let fixedSize : Size ?
144
+ /// The rect that contains this entity.
145
+ /// The entity MUST use this rect for rendering.
146
+ public var currentRect : Rect ? {
147
+ if let size = mostRecentSize {
148
+ return Rect ( topLeft: topLeft, size: size)
149
+ } else {
150
+ return nil
151
+ }
152
+ }
129
153
130
- public init ( name: String ? = nil ,
131
- topLeft: Point = Point . zero, fixedSize: Size ? ) {
132
- self . owningContainer = nil
133
- self . topLeft = topLeft
134
- self . _currentCalculatedSize = fixedSize
135
- self . fixedSize = fixedSize
136
- self . previousCalculatedSize = nil
154
+ /// Returns an array of all ancestors of this `ContainableRenderableEntity`.
155
+ /// This includes this containers parent, as well as its grandparent,
156
+ /// great grandparent, etc.
157
+ public var ancestors : [ RenderableEntityContainer ] {
158
+ var ancestors = [ RenderableEntityContainer] ( )
159
+ if let parent = owningContainer {
160
+ ancestors. append ( parent)
161
+ ancestors. append ( contentsOf: parent. ancestors)
162
+ }
137
163
138
- super . init ( name : name )
164
+ return ancestors
139
165
}
140
-
141
166
167
+ // ****************************************************************
168
+ // API FOLLOWS
169
+ // These functions should be over-ridden by descendant classes
170
+ // ****************************************************************
142
171
172
+ /// Calculates a new size based unpon the contents of this entity.
173
+ /// This will be automatically invoked and should NOT be directly
174
+ /// called.
175
+ open func calculateSize( ) -> Size ? {
176
+ return nil
177
+ }
178
+
179
+ /// Handles size recalculation if necessary.
180
+ /// If overriden, invoke `super.calculate(canvasSize:canvasSize)`
181
+ /// before adding custom logic to recalculate size if necessary.
182
+ open override func calculate( canvasSize: Size ) {
183
+ // If we don't have a size, we calculate it here.
184
+ if currentCalculatedSize == nil {
185
+ setCurrentCalculatedSize ( )
186
+ }
187
+ }
188
+
189
+ /// Invoked to inform an entity that its size has changed.
190
+ /// Descendant classes should only note this change and take action
191
+ /// later in *calculate()*.
192
+ /// The potential change in size may be due to a new, external size or a new
193
+ /// calculated size, either of which MAY result in an actual change in rendered
194
+ /// size.
195
+ open func sizeChanged( ) {
196
+ }
197
+
198
+ /// Invoked to inform an entity that its *topLeft* has changed.
199
+ /// Descendant classes should only note this change and take action
200
+ /// later in *calculate()*.
201
+ open func topLeftChanged( ) {
202
+ }
143
203
}
0 commit comments