summaryrefslogtreecommitdiffstats
path: root/layout
diff options
context:
space:
mode:
authorSean E. Russell <ser@ser1.net>2020-02-20 08:19:15 -0600
committerSean E. Russell <ser@ser1.net>2020-02-20 08:19:15 -0600
commit7b09a00230e059129e010039a159ef9ce7aecc11 (patch)
tree7583287cfc2fdc277d7d361ec484e17c3016a0af /layout
parent66ad0f878540dee82ae2c2b5c561754b6480a157 (diff)
Issue #56. Slight improvement in layout algorithm. Still doesn't handle > 2 columns well, but it's more correct and lays the foundation for a correct solution. It's clear, however, that a full table model parser will require a substantial rewrite and, possibly, a change in the layout syntax. That would add substantial complexity, so maybe for some future effort. I'll fix the basic column layout (rowspans at the edges), and then shelve it.
Diffstat (limited to 'layout')
-rw-r--r--layout/layout.go39
-rw-r--r--layout/layout_test.go27
2 files changed, 51 insertions, 15 deletions
diff --git a/layout/layout.go b/layout/layout.go
index 359b47e..0ab6b54 100644
--- a/layout/layout.go
+++ b/layout/layout.go
@@ -31,17 +31,17 @@ var widgetNames []string = []string{"cpu", "disk", "mem", "temp", "net", "procs"
func Layout(wl layout, c gotop.Config) (*MyGrid, error) {
rowDefs := wl.Rows
- uiRows := make([]ui.GridItem, 0)
+ uiRows := make([][]interface{}, 0)
numRows := countNumRows(wl.Rows)
- var uiRow ui.GridItem
+ var uiRow []interface{}
for len(rowDefs) > 0 {
uiRow, rowDefs = processRow(c, numRows, rowDefs)
uiRows = append(uiRows, uiRow)
}
rgs := make([]interface{}, 0)
+ rh := 1.0 / float64(len(uiRows))
for _, ur := range uiRows {
- ur.HeightRatio = ur.HeightRatio / float64(numRows)
- rgs = append(rgs, ur)
+ rgs = append(rgs, ui.NewRow(rh, ur...))
}
grid := &MyGrid{ui.NewGrid(), nil, nil}
grid.Set(rgs...)
@@ -58,11 +58,10 @@ func Layout(wl layout, c gotop.Config) (*MyGrid, error) {
// if there's a row span widget in the row; in this case, it'll consume as many
// rows as the largest row span object in the row, and produce an uber-row
// containing all that stuff. It returns a slice without the consumed elements.
-func processRow(c gotop.Config, numRows int, rowDefs [][]widgetRule) (ui.GridItem, [][]widgetRule) {
- // FIXME: 3\:A 2\:B\nC should stop consuming rows when all columns are full
+func processRow(c gotop.Config, numRows int, rowDefs [][]widgetRule) ([]interface{}, [][]widgetRule) {
// Recursive function #3. See the comment in deepFindProc.
if len(rowDefs) < 1 {
- return ui.GridItem{}, [][]widgetRule{}
+ return nil, [][]widgetRule{}
}
// The height of the tallest widget in this row; the number of rows that
// will be consumed, and the overall height of the row that will be
@@ -87,6 +86,7 @@ func processRow(c gotop.Config, numRows int, rowDefs [][]widgetRule) (ui.GridIte
columns = append(columns, make([]interface{}, 0))
}
colHeights := make([]int, numCols)
+outer:
for i, row := range processing {
// A definition may fill up the columns before all rows are consumed,
// e.g. wid1/2 wid2/2. This block checks for that and, if it occurs,
@@ -102,16 +102,25 @@ func processRow(c gotop.Config, numRows int, rowDefs [][]widgetRule) (ui.GridIte
rowDefs = append(processing[i:], rowDefs...)
break
}
- // Not all rows have been consumed, so go ahead and place the row's widgets in columns
- for _, wid := range row {
- for j, ch := range colHeights {
- if ch+wid.Height <= maxHeight {
- widget := makeWidget(c, wid)
- columns[j] = append(columns[j], ui.NewRow(float64(wid.Height)/float64(maxHeight), widget))
- colHeights[j] += wid.Height
+ // Not all rows have been consumed, so go ahead and place the row's
+ // widgets in columns
+ for w, widg := range row {
+ placed := false
+ for k := w; k < len(colHeights); k++ { // there are enough columns
+ ch := colHeights[k]
+ if ch+widg.Height <= maxHeight {
+ widget := makeWidget(c, widg)
+ columns[k] = append(columns[k], ui.NewRow(float64(widg.Height)/float64(maxHeight), widget))
+ colHeights[k] += widg.Height
+ placed = true
break
}
}
+ // If all columns are full, break out, return the row, and continue processing
+ if !placed {
+ rowDefs = processing[i:]
+ break outer
+ }
}
}
var uiColumns []interface{}
@@ -121,7 +130,7 @@ func processRow(c gotop.Config, numRows int, rowDefs [][]widgetRule) (ui.GridIte
}
}
- return ui.NewRow(1.0/float64(numRows), uiColumns...), rowDefs
+ return uiColumns, rowDefs
}
type Metric interface {
diff --git a/layout/layout_test.go b/layout/layout_test.go
index d1f016d..568bbee 100644
--- a/layout/layout_test.go
+++ b/layout/layout_test.go
@@ -101,6 +101,33 @@ func TestParsing(t *testing.T) {
assert.Equal(t, 1, l.Rows[1][0].Height)
assert.Equal(t, 1.0, l.Rows[1][0].Weight)
}},
+ {"cpu/2 mem/1 6:procs\n3:temp/1 2:disk/2\npower\nnet procs", func(l layout) {
+ assert.Equal(t, 4, len(l.Rows))
+ // First row
+ assert.Equal(t, 3, len(l.Rows[0]))
+ assert.Equal(t, 1, l.Rows[0][0].Height)
+ assert.Equal(t, 0.5, l.Rows[0][0].Weight)
+ assert.Equal(t, 1, l.Rows[0][1].Height)
+ assert.Equal(t, 0.25, l.Rows[0][1].Weight)
+ assert.Equal(t, 6, l.Rows[0][2].Height)
+ assert.Equal(t, 0.25, l.Rows[0][2].Weight)
+ // Second row
+ assert.Equal(t, 2, len(l.Rows[1]))
+ assert.Equal(t, 3, l.Rows[1][0].Height)
+ assert.Equal(t, 1/3.0, l.Rows[1][0].Weight)
+ assert.Equal(t, 2, l.Rows[1][1].Height)
+ assert.Equal(t, 2/3.0, l.Rows[1][1].Weight)
+ // Third row
+ assert.Equal(t, 1, len(l.Rows[2]))
+ assert.Equal(t, 1, l.Rows[2][0].Height)
+ assert.Equal(t, 1.0, l.Rows[2][0].Weight)
+ // Fourth row
+ assert.Equal(t, 2, len(l.Rows[3]))
+ assert.Equal(t, 1, l.Rows[3][0].Height)
+ assert.Equal(t, 0.5, l.Rows[3][0].Weight)
+ assert.Equal(t, 1, l.Rows[3][1].Height)
+ assert.Equal(t, 0.5, l.Rows[3][1].Weight)
+ }},
}
for _, tc := range tests {