Enter every row a read pins before walking on, and skip a cell outside an entered ancestor's row
This commit is contained in:
@@ -965,9 +965,10 @@ renamed or retyped line is a major.
|
|||||||
- **The rows of a table are alternatives.** Only one row renders, so a cell in one
|
- **The rows of a table are alternatives.** Only one row renders, so a cell in one
|
||||||
row and a cell in another never meet, and each may select its own row of another
|
row and a cell in another never meet, and each may select its own row of another
|
||||||
table; the cells of one row, and whatever they reach, do meet, and so does the
|
table; the cells of one row, and whatever they reach, do meet, and so does the
|
||||||
format beside them. The family fence replays the reads of each row apart,
|
format beside them. The rule the fence applies is that two reads meet unless
|
||||||
together with the reads outside any row. A choice's items get no such treatment
|
they sit in two rows of one table, or in a row outside a selected ancestor's. A
|
||||||
yet: two items selecting different rows are still refused.
|
choice's items get no such treatment yet: two items selecting different rows
|
||||||
|
are still refused.
|
||||||
- **A path is walked once without drawing before it is walked for real.** A path
|
- **A path is walked once without drawing before it is walked for real.** A path
|
||||||
that fails below its first level then moves no seeded stream, at the cost of one
|
that fails below its first level then moves no seeded stream, at the cost of one
|
||||||
draw-free walk per call, which allocates nothing.
|
draw-free walk per call, which allocates nothing.
|
||||||
|
|||||||
@@ -363,8 +363,7 @@ func (w *drawWalk) walk(n node, at drawAt) {
|
|||||||
}
|
}
|
||||||
for _, e := range renderEdges(n) {
|
for _, e := range renderEdges(n) {
|
||||||
if cell, isCell := e.to.(*template); isCell && cell.cellOf != nil {
|
if cell, isCell := e.to.(*template); isCell && cell.cellOf != nil {
|
||||||
// A row already entered renders only its own cell of this column.
|
if at.alt.excludes(cell) {
|
||||||
if r, in := at.alt.rowOf(cell.cellOf); in && r != cell.cellRow {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
w.edge(n, e, drawAt{at.group, at.route, at.alt.enter(cell.cellOf, cell.cellRow)})
|
w.edge(n, e, drawAt{at.group, at.route, at.alt.enter(cell.cellOf, cell.cellRow)})
|
||||||
@@ -374,22 +373,31 @@ func (w *drawWalk) walk(n node, at drawAt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// excludes reports whether a cell's row cannot render with the rows entered: another
|
||||||
|
// row of its table, or a row outside an entered ancestor's.
|
||||||
|
func (s rowSet) excludes(cell *template) bool {
|
||||||
|
for _, p := range s {
|
||||||
|
if p.t == cell.cellOf {
|
||||||
|
return p.row != cell.cellRow
|
||||||
|
}
|
||||||
|
if cell.cellOf.descends(p.t) && !cell.cellOf.under(cell.cellRow, p.t, p.row) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// edge records the reference an edge reads, then walks on with every row the read
|
||||||
|
// pins entered, so a selected row renders only its own cells.
|
||||||
func (w *drawWalk) edge(from node, e renderEdge, at drawAt) {
|
func (w *drawWalk) edge(from node, e renderEdge, at drawAt) {
|
||||||
var tr *tableRead
|
|
||||||
if a, reads := refRead(from, e.label); reads {
|
if a, reads := refRead(from, e.label); reads {
|
||||||
tr = tableReadOf(from.(*template).fields[a.key], a, e.to)
|
tr := tableReadOf(from.(*template).fields[a.key], a, e.to)
|
||||||
if k := (drawKey{at.group, a.path, at.alt.key()}); !w.read[k] {
|
if k := (drawKey{at.group, a.path, at.alt.key()}); !w.read[k] {
|
||||||
w.read[k] = true
|
w.read[k] = true
|
||||||
w.reads = append(w.reads, pathRead{at, a, tr})
|
w.reads = append(w.reads, pathRead{at, a, tr})
|
||||||
}
|
}
|
||||||
}
|
if tr != nil {
|
||||||
// A read that pins the column's table renders that row's cell alone.
|
tr.pins.each(func(t *table, r int) { at.alt = at.alt.enter(t, r) })
|
||||||
if c, isColumn := e.to.(*column); isColumn && tr != nil {
|
|
||||||
if r, pinned := tr.pins.pinned(c.t); pinned {
|
|
||||||
if cell := c.t.cellNode(r, c.i); cell != nil {
|
|
||||||
w.walk(cell, drawAt{at.group, at.route, at.alt.enter(c.t, r)})
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.walk(e.to, at)
|
w.walk(e.to, at)
|
||||||
|
|||||||
@@ -465,6 +465,16 @@ func (t *table) descendant(name string) *table {
|
|||||||
// parentRow is the row of t's parent that row r links to.
|
// parentRow is the row of t's parent that row r links to.
|
||||||
func (t *table) parentRow(r int) int { return t.parentT.byKey[t.cell(r, t.parent)] }
|
func (t *table) parentRow(r int) int { return t.parentT.byKey[t.cell(r, t.parent)] }
|
||||||
|
|
||||||
|
// descends reports whether a is an ancestor of t.
|
||||||
|
func (t *table) descends(a *table) bool {
|
||||||
|
for p := t.parentT; p != nil; p = p.parentT {
|
||||||
|
if p == a {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// under reports whether row r of t sits inside row pr of ancestor a.
|
// under reports whether row r of t sits inside row pr of ancestor a.
|
||||||
func (t *table) under(r int, a *table, pr int) bool {
|
func (t *table) under(r int, a *table, pr int) bool {
|
||||||
for c, row := t, r; c.parentT != nil; c, row = c.parentT, c.parentRow(row) {
|
for c, row := t, r; c.parentT != nil; c, row = c.parentT, c.parentRow(row) {
|
||||||
|
|||||||
Reference in New Issue
Block a user