Skip to content

Commit 27ef402

Browse files
committed
fix footer + onLayoutChange propagation on view hide
1 parent 94699db commit 27ef402

File tree

1 file changed

+31
-9
lines changed

1 file changed

+31
-9
lines changed

runtime/ui/layout/manager.go

+31-9
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ import (
66
)
77

88
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
1112
}
1213

1314
func NewManager() *Manager {
@@ -137,7 +138,7 @@ func (lm *Manager) layoutColumns(g *gocui.Gui, area Area) (Area, error) {
137138
return area, nil
138139
}
139140

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 {
141142
// layout footers top down (which is why the list is reversed). Top down is needed due to border overlap.
142143
if elements, exists := lm.elements[LocationFooter]; exists {
143144
for idx := len(elements) - 1; idx >= 0; idx-- {
@@ -147,7 +148,7 @@ func (lm *Manager) layoutFooters(g *gocui.Gui, area Area, footerHeights []int) (
147148
for oIdx := 0; oIdx <= idx; oIdx++ {
148149
bottomPadding += footerHeights[oIdx]
149150
}
150-
topY = area.maxX - bottomPadding - height
151+
topY = area.maxY - bottomPadding - height
151152
// +1 for border
152153
bottomY = topY + height + 1
153154

@@ -157,11 +158,11 @@ func (lm *Manager) layoutFooters(g *gocui.Gui, area Area, footerHeights []int) (
157158
err := element.Layout(g, area.minX, topY, area.maxX, bottomY)
158159
if err != nil {
159160
logrus.Errorf("failed to layout '%s' footer: %+v", element.Name(), err)
160-
return area, err
161+
return err
161162
}
162163
}
163164
}
164-
return area, nil
165+
return nil
165166
}
166167

167168
func (lm *Manager) notifyLayoutChange() error {
@@ -184,7 +185,9 @@ func (lm *Manager) notifyLayoutChange() error {
184185
// 2. since there are borders, in order for it to appear as if there aren't any spaces for borders, the views must
185186
// overlap. To prevent screen artifacts, all elements must be layedout from the top of the screen to the bottom.
186187
func (lm *Manager) Layout(g *gocui.Gui) error {
188+
var headerAreaChanged, footerAreaChanged, columnAreaChanged bool
187189

190+
// grab the latest screen size and compare with the last layout
188191
curMaxX, curMaxY := g.Size()
189192
area := Area{
190193
minX: -1,
@@ -199,31 +202,50 @@ func (lm *Manager) Layout(g *gocui.Gui) error {
199202
}
200203
lm.lastX, lm.lastY = curMaxX, curMaxY
201204

205+
// pass 1: plan and layout elements
206+
202207
// plan and layout all headers
203208
area, err := lm.layoutHeaders(g, area)
204209
if err != nil {
205210
return err
206211
}
207212

213+
if area != lm.lastHeaderArea {
214+
headerAreaChanged = true
215+
}
216+
lm.lastHeaderArea = area
217+
208218
// plan all footers, don't layout until all columns have been layedout. This is necessary since we must layout from
209219
// top to bottom, but we need the real estate planned for the footers to determine the bottom of the columns.
210220
var footerArea = area
211221
area, footerHeights := lm.planFooters(g, area)
212222

223+
if area != lm.lastFooterArea {
224+
footerAreaChanged = true
225+
}
226+
lm.lastFooterArea = area
227+
213228
// plan and layout the main columns
214229
area, err = lm.layoutColumns(g, area)
215230
if err != nil {
216231
return nil
217232
}
218233

234+
if area != lm.lastColumnArea {
235+
columnAreaChanged = true
236+
}
237+
lm.lastColumnArea = area
238+
219239
// 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)
221241
if err != nil {
222242
return nil
223243
}
224244

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 {
227249
return lm.notifyLayoutChange()
228250
}
229251

0 commit comments

Comments
 (0)