Skip to content

Commit 09c57ae

Browse files
author
Camden Thomson
committed
- Redesigned ContainableRenderableEntity and RenderableEntityContainer to use more efficient calculation methods and provide more default functionality.
- entities are now auto-resized based on output of new overridable `calculateSize()` method (invoked as needed). - reduced unnecessary update calls and decreased framecount required to update `RenderableEntityContainer` size from 2 frames to 1 frame. - Added more catches in dispatcher to prevent warning messages from firing for entity events unless they are relevant.
1 parent 13c8203 commit 09c57ae

4 files changed

+261
-196
lines changed
+124-64
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
Scenes provides a Swift object library with support for renderable entities,
33
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
55
This program is free software: you can redistribute it and/or modify
66
it under the terms of the GNU General Public License as published by
77
the Free Software Foundation, either version 3 of the License, or
@@ -28,90 +28,108 @@ import Igis
2828
/// 5. Containers will resize and reposition their contained entities and
2929
/// maintaining the *currentCalculatedSize* as the minimum size
3030
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
3950

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)
4752
}
4853

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()
5361
}
5462

55-
56-
// ********************************************************************************
63+
// ****************************************************************
5764
// API FOLLOWS
58-
// ********************************************************************************
65+
// ****************************************************************
5966

6067
/// The topLeft point of the entity
6168
/// When set, this entity must reposition accordingly.
6269
public var topLeft : Point {
6370
didSet {
64-
topLeftChanged()
71+
if oldValue != topLeft {
72+
topLeftChanged()
73+
}
6574
}
6675
}
6776

6877
/// The externally specified size of the entity, overriding
6978
/// the *currentCalculatedSize*.
7079
public var externalSize : Size? {
7180
didSet {
72-
sizeChanged()
81+
if oldValue != externalSize {
82+
sizeChanged()
83+
}
7384
}
7485
}
7586

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?
78100
/// Descendant classes must set this value to nil when it is necessary to
79101
/// 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.
84104
public var currentCalculatedSize : Size? {
85105
get {
86106
return _currentCalculatedSize
87107
}
88108
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 {
97122
_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()
102128
}
103-
}
104-
sizeChanged()
129+
}
105130
}
106131
}
107132

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-
115133
/// The most recently available calculated size
116134
public var mostRecentCalculatedSize : Size? {
117135
return currentCalculatedSize ?? previousCalculatedSize
@@ -123,21 +141,63 @@ open class ContainableRenderableEntity : RenderableEntity {
123141
return externalSize ?? mostRecentCalculatedSize
124142
}
125143

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+
}
129153

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+
}
137163

138-
super.init(name:name)
164+
return ancestors
139165
}
140-
141166

167+
// ****************************************************************
168+
// API FOLLOWS
169+
// These functions should be over-ridden by descendant classes
170+
// ****************************************************************
142171

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+
}
143203
}

0 commit comments

Comments
 (0)