6
6
)
7
7
8
8
type Manager struct {
9
- lastX , lastY int
10
- elements map [Location ][]Layout
9
+ lastX , lastY int
10
+ lastHeaderArea , lastFooterArea , lastColumnArea Area
11
+ elements map [Location ][]Layout
11
12
}
12
13
13
14
func NewManager () * Manager {
@@ -137,7 +138,7 @@ func (lm *Manager) layoutColumns(g *gocui.Gui, area Area) (Area, error) {
137
138
return area , nil
138
139
}
139
140
140
- func (lm * Manager ) layoutFooters (g * gocui.Gui , area Area , footerHeights []int ) ( Area , error ) {
141
+ func (lm * Manager ) layoutFooters (g * gocui.Gui , area Area , footerHeights []int ) error {
141
142
// layout footers top down (which is why the list is reversed). Top down is needed due to border overlap.
142
143
if elements , exists := lm .elements [LocationFooter ]; exists {
143
144
for idx := len (elements ) - 1 ; idx >= 0 ; idx -- {
@@ -147,7 +148,7 @@ func (lm *Manager) layoutFooters(g *gocui.Gui, area Area, footerHeights []int) (
147
148
for oIdx := 0 ; oIdx <= idx ; oIdx ++ {
148
149
bottomPadding += footerHeights [oIdx ]
149
150
}
150
- topY = area .maxX - bottomPadding - height
151
+ topY = area .maxY - bottomPadding - height
151
152
// +1 for border
152
153
bottomY = topY + height + 1
153
154
@@ -157,11 +158,11 @@ func (lm *Manager) layoutFooters(g *gocui.Gui, area Area, footerHeights []int) (
157
158
err := element .Layout (g , area .minX , topY , area .maxX , bottomY )
158
159
if err != nil {
159
160
logrus .Errorf ("failed to layout '%s' footer: %+v" , element .Name (), err )
160
- return area , err
161
+ return err
161
162
}
162
163
}
163
164
}
164
- return area , nil
165
+ return nil
165
166
}
166
167
167
168
func (lm * Manager ) notifyLayoutChange () error {
@@ -184,7 +185,9 @@ func (lm *Manager) notifyLayoutChange() error {
184
185
// 2. since there are borders, in order for it to appear as if there aren't any spaces for borders, the views must
185
186
// overlap. To prevent screen artifacts, all elements must be layedout from the top of the screen to the bottom.
186
187
func (lm * Manager ) Layout (g * gocui.Gui ) error {
188
+ var headerAreaChanged , footerAreaChanged , columnAreaChanged bool
187
189
190
+ // grab the latest screen size and compare with the last layout
188
191
curMaxX , curMaxY := g .Size ()
189
192
area := Area {
190
193
minX : - 1 ,
@@ -199,31 +202,50 @@ func (lm *Manager) Layout(g *gocui.Gui) error {
199
202
}
200
203
lm .lastX , lm .lastY = curMaxX , curMaxY
201
204
205
+ // pass 1: plan and layout elements
206
+
202
207
// plan and layout all headers
203
208
area , err := lm .layoutHeaders (g , area )
204
209
if err != nil {
205
210
return err
206
211
}
207
212
213
+ if area != lm .lastHeaderArea {
214
+ headerAreaChanged = true
215
+ }
216
+ lm .lastHeaderArea = area
217
+
208
218
// plan all footers, don't layout until all columns have been layedout. This is necessary since we must layout from
209
219
// top to bottom, but we need the real estate planned for the footers to determine the bottom of the columns.
210
220
var footerArea = area
211
221
area , footerHeights := lm .planFooters (g , area )
212
222
223
+ if area != lm .lastFooterArea {
224
+ footerAreaChanged = true
225
+ }
226
+ lm .lastFooterArea = area
227
+
213
228
// plan and layout the main columns
214
229
area , err = lm .layoutColumns (g , area )
215
230
if err != nil {
216
231
return nil
217
232
}
218
233
234
+ if area != lm .lastColumnArea {
235
+ columnAreaChanged = true
236
+ }
237
+ lm .lastColumnArea = area
238
+
219
239
// layout the footers according to the original available area and planned heights
220
- area , err = lm .layoutFooters (g , footerArea , footerHeights )
240
+ err = lm .layoutFooters (g , footerArea , footerHeights )
221
241
if err != nil {
222
242
return nil
223
243
}
224
244
225
- // notify everyone of a layout change (allow to update and render)
226
- if hasResized {
245
+ // pass 2: notify everyone of a layout change (allow to update and render)
246
+ // note: this may mean that each element will update and rerender, which may cause a secondary layout call.
247
+ // the conditions which we notify elements of layout changes must be very selective!
248
+ if hasResized || headerAreaChanged || footerAreaChanged || columnAreaChanged {
227
249
return lm .notifyLayoutChange ()
228
250
}
229
251
0 commit comments