import blit
import bitops
import illwill
import math
import unicode
type
LayoutTag* {.pure.} = enum
center, left, right,
floatCenter
Layer* = ref object
blit*: Blit
src*: Pt
dst*: Rect
tag*: LayoutTag
Comp* = ref object
size: Size
tb: illwill.TerminalBuffer
layers: seq[Layer]
focus: int
proc size*(l: Layer): Size = l.dst.size()
proc size*(c: Comp): Size = c.size
proc contains*(l: Layer, p: Pt): bool =
l.dst.contains(p) and l.blit.contains(p - l.src)
proc get*(l: Layer, dst: Pt): Char =
var src = Pt(
x: l.src.x + (dst.x - l.dst.lo.x),
y: l.src.y + (dst.y - l.dst.lo.y))
if l.blit.contains(src):
return l.blit.get(src)
return NO_CHAR
proc get*(c: Comp, p: Pt): TerminalChar =
return c.tb[p.x, p.y]
proc newLayer*(size: Size): Layer =
Layer(blit: newBlit(size), tag: LayoutTag.center)
proc newLayer*(blit: Blit): Layer =
Layer(blit: blit, tag: LayoutTag.center)
proc newComp*(size: Size): Comp =
Comp(size: size,
tb: newTerminalBuffer(size.w, size.h),
layers: newSeq[Layer]())
proc toplayers(c: Comp): array[LayoutTag, Layer] =
var res: array[LayoutTag, Layer]
for layer in c.layers:
if res[layer.tag] == nil:
res[layer.tag] = layer
return res
proc layout(c: var Comp) =
let ls = toplayers(c)
var present = 0
let full = rectFromSize(c.size)
if ls[left] != nil:
present = bitor(present, 0b100)
ls[left].dst = full
if ls[center] != nil:
present = bitor(present, 0b010)
ls[center].dst = full
if ls[right] != nil:
present = bitor(present, 0b001)
ls[right].dst = full
case present
of 0b010, 0b100, 0b001: discard
of 0b110:
let split = int(ceil(c.size.w.float * 0.33))
ls[left].dst.hi.x = split - 1
ls[center].dst.lo.x = split
of 0b011:
let split = int(ceil(c.size.w.float * 0.67))
ls[center].dst.hi.x = split - 1
ls[right].dst.lo.x = split
of 0b101:
let split = int(c.size.w.float * 0.5)
ls[left].dst.hi.x = split - 1
ls[right].dst.lo.x = split
of 0b111:
let lsplit = int(ceil(c.size.w.float * 0.25))
let rsplit = int(ceil(c.size.w.float * 0.75))
ls[left].dst.hi.x = lsplit - 1
ls[center].dst.lo.x = lsplit
ls[center].dst.hi.x = rsplit - 1
ls[right].dst.lo.x = rsplit
else: discard
proc paint*(c: var Comp) =
c.layout()
c.tb.clear()
for index, layer in c.layers:
for point in pointsInside(@[layer.dst]):
let ch = layer.get(point)
c.tb[point.x, point.y] = TerminalChar(
ch: ch[0],
fg: fgNone,
bg: if index == c.focus: bgBlack else: bgWhite,
style: {})
c.tb.display()
proc pushlayer*(c: var Comp, l: Layer) =
c.layers.insert(l, 0)
c.focus = c.layers.len - 1
proc poplayer*(c: var Comp) =
let i = c.layers.len - 1
c.layers.delete(i)
c.focus = 0
proc focused*(c: Comp): Layer =
return c.layers[c.focus]
proc focus*(c: var Comp, layer: Layer) =
c.focus = find(c.layers, layer)
proc `size=`*(c: var Comp, s: Size) =
c.tb = newTerminalBuffer(s.w, s.h)
c.size = s
proc print*(b: Comp) =
for j in 0..(b.size.h - 1):
for i in 0..(b.size.w - 1):
var c = b.get(newPt(i, j))
stdout.write(c.ch.toUTF8)
stdout.write('\n')
proc printdebug*(c: Comp) =
echo c.layers[0].src, " -> ", c.layers[0].dst