diff options
| -rw-r--r-- | tui/layout.go | 123 |
1 files changed, 109 insertions, 14 deletions
diff --git a/tui/layout.go b/tui/layout.go index 1b3c3ed..210924f 100644 --- a/tui/layout.go +++ b/tui/layout.go @@ -7,12 +7,13 @@ import ( ) type Box struct { + id string Width, Height BoxSize Dir Direction Overflow bool - Scroll int Style *Style Margins [4]int + Scroll *ScrollState text []textRun computedLines [][]textRun children []*Box @@ -68,10 +69,29 @@ type rect struct { max [2]int } -type BoxEvent struct { +type ScrollState struct { + at string + offset int + absolute int + atFirst bool + atLast bool } -type TextEvent struct { +func (s *ScrollState) ToStart() { + *s = ScrollState {} +} + +func (s *ScrollState) AtFirst() bool { + return s.atFirst +} + +func (s *ScrollState) AtLast() bool { + return s.atLast +} + +func (s *ScrollState) Scroll(amnt int) { + s.offset += amnt + s.absolute += amnt } var layout struct { @@ -89,23 +109,22 @@ func top() *Box { return layout.stack[len(layout.stack) - 1] } -func Push(id string, box Box) BoxEvent { +func Push(id string, box Box) { if len(layout.stack) > 0 { top().children = append(top().children, &box) } layout.stack = append(layout.stack, &box) layout.front[id] = &box + box.id = id for axis, value := range box.axes() { if value >= 0 { box.computedSize[axis] = int(value) } } - return BoxEvent {} } -func Text(text string, style *Style) TextEvent { +func Text(text string, style *Style) { top().text = append(top().text, textRun {text, style}) - return TextEvent {} } func Pop() { @@ -292,12 +311,65 @@ func (b *Box) computePositions(axis int) { if b.Dir.reverse() { pos -= c.computedSize[axis] } + c.computedPosition = pos - c.computedRect.min[axis] = b.computedRect.min[axis] + pos - c.computedRect.max[axis] = c.computedRect.min[axis] + c.computedSize[axis] + + if b.Scroll != nil && b.Scroll.at != "" && b.Scroll.at == c.id { + p := c.computedPosition + if b.Dir.reverse() { + p = b.computedSize[axis] - p + } + b.Scroll.absolute = p + if !b.Dir.reverse() { + b.Scroll.absolute += b.Scroll.offset + } else { + b.Scroll.absolute += b.Scroll.offset + } + } + if !b.Dir.reverse() { pos += c.computedSize[axis] } + } + if b.Scroll != nil { + var first *Box + var last *Box + for _, c := range b.children { + if !b.Dir.reverse() { + c.computedPosition -= b.Scroll.absolute + } else { + c.computedPosition += b.Scroll.absolute + } + if c.computedPosition > b.computedRect.min[axis] && + c.computedPosition < b.computedRect.max[axis] { + if first == nil { + first = c + } + last = c + } + } + if first == b.children[0] { + b.Scroll.atFirst = true + } + if last == b.children[len(b.children) - 1] { + b.Scroll.atLast = true + } + if first != nil { + p := first.computedPosition + if b.Dir.reverse() { + p = b.computedSize[axis] - p + } + b.Scroll.offset = -p + b.Scroll.at = first.id + } + if b.Scroll.absolute == 0 { + b.Scroll.at = "" + b.Scroll.offset = 0 + } + } + for _, c := range b.children { + c.computedRect.min[axis] = b.computedRect.min[axis] + c.computedPosition + c.computedRect.max[axis] = c.computedRect.min[axis] + c.computedSize[axis] c.computePositions(axis) } } else { @@ -309,12 +381,22 @@ func (b *Box) computePositions(axis int) { } } -func (b *Box) drawComputed(parentStyle Style) { +func (b *Box) drawComputed(parentRect rect, parentStyle Style) { + var viewRect rect = parentRect; + for i := 0; i < 2; i++ { + bMin := b.computedRect.min[i] + b.Margins[i * 2] + viewRect.min[i] = max(bMin, parentRect.min[i]) + } + for i := 0; i < 2; i++ { + bMax := b.computedRect.max[i] - b.Margins[i * 2 + 1] + viewRect.max[i] = min(bMax, parentRect.max[i]) + } + style := parentStyle if b.Style != nil { style = *b.Style - for y := b.computedRect.min[1]; y < b.computedRect.max[1]; y++ { - for x := b.computedRect.min[0]; x < b.computedRect.max[0]; x++ { + for y := viewRect.min[1]; y < viewRect.max[1]; y++ { + for x := viewRect.min[0]; x < viewRect.max[0]; x++ { WriteAt(x, y, " ", style) } } @@ -325,6 +407,15 @@ func (b *Box) drawComputed(parentStyle Style) { if y > b.computedRect.max[1] - b.Margins[3] { break } + if y < b.computedRect.min[1] + b.Margins[2] { + continue + } + if y > parentRect.max[1] { + break + } + if y < parentRect.min[1] { + continue + } for _, t := range l { var s Style if t.style != nil { @@ -336,7 +427,7 @@ func (b *Box) drawComputed(parentStyle Style) { } } for _, c := range b.children { - c.drawComputed(style) + c.drawComputed(viewRect, style) } } @@ -357,5 +448,9 @@ func DrawLayout() { b.solve(axis) b.computePositions(axis) } - b.drawComputed(DefaultStyle) + var parentRect rect + size := Size() + parentRect.max = [2]int {size.Width, size.Height} + b.computedRect = parentRect + b.drawComputed(parentRect, DefaultStyle) } |
