git.haldean.org e / 266daf2
layout support haldean 1 year, 6 months ago
3 changed file(s) with 157 addition(s) and 114 deletion(s). Raw diff Collapse all Expand all
0 import illwill
10 import unicode
21
32 type
1615 stride: int
1716 Blit* = RectBuf[Char]
1817
19 Layer* = ref object
20 blit: Blit
21 src: Pt
22 dst: Rect
23 invalid: Rect
24
25 Comp* = ref object
26 size: Size
27 tb*: illwill.TerminalBuffer
28 layers: seq[Layer]
29 srclayer: RectBuf[int]
30 fullrepaint: bool
31
3218 const NO_CHAR*: Char = (Rune(' '), Style(0xFF))
33 const NO_LAYER: int = -1
3419
3520 ## POINT MATH
3621
37 proc `+`(p0: Pt, p1: Pt): Pt =
22 proc `+`*(p0: Pt, p1: Pt): Pt =
3823 Pt(x: p0.x + p1.x, y: p0.y + p1.y)
3924
40 proc `-`(p0: Pt, p1: Pt): Pt =
25 proc `-`*(p0: Pt, p1: Pt): Pt =
4126 Pt(x: p0.x - p1.x, y: p0.y - p1.y)
4227
43 proc `+=`(p0: var Pt, p1: Pt) =
28 proc `+=`*(p0: var Pt, p1: Pt) =
4429 p0.x += p1.x
4530 p0.y += p1.y
4631
5641 return 0
5742 return r.hi.y - r.lo.y + 1
5843
44 proc size*(r: Rect): Size =
45 Size(w: r.width(), h: r.height())
46
5947 proc isempty*(r: Rect): bool = r.width() <= 0 or r.height() <= 0
6048
6149 proc width*[T](b: RectBuf[T]): int = b.stride
6654 proc size*[T](b: RectBuf[T]): Size =
6755 Size(w: b.width(), h: b.height())
6856
69 proc size*(c: Comp): Size = c.size
70
7157 proc contains*(r: Rect, p: Pt): bool =
7258 r.lo.x <= p.x and p.x <= r.hi.x and
7359 r.lo.y <= p.y and p.y <= r.hi.y
7561 proc contains*[T](b: RectBuf[T], p: Pt): bool =
7662 0 <= p.x and p.x < b.width() and
7763 0 <= p.y and p.y < b.height()
78
79 proc contains*(l: Layer, p: Pt): bool =
80 l.dst.contains(p) and l.blit.contains(p - l.src)
8164
8265 proc `+=`*(r0: var Rect, r1: Rect) =
8366 if r1.isempty():
10487 proc get*[T](b: RectBuf[T], p: Pt): T =
10588 b.c[b.index(p)]
10689
107 proc get*(l: Layer, dst: Pt): Char =
108 var src = Pt(
109 x: l.src.x + (dst.x - l.dst.lo.x),
110 y: l.src.y + (dst.y - l.dst.lo.y))
111 if l.blit.contains(src):
112 return l.blit.get(src)
113 return NO_CHAR
114
115 proc get*(c: Comp, p: Pt): Char =
116 let layerindex = c.srclayer.get(p)
117 if layerindex == NO_LAYER:
118 return NO_CHAR
119 return c.layers[layerindex].get(p)
120
12190 proc resize*[T](b: var RectBuf[T], size: Size) =
12291 let s = size.w * size.h
12392 b.c = newSeq[T](s)
12897 proc newPt*(x, y: int): Pt =
12998 Pt(x: x, y: y)
13099
131 proc emptyRect(): Rect =
100 proc emptyRect*(): Rect =
132101 Rect(lo: newPt(0, 0), hi: newPt(-1, -1))
133102
134103 proc rectFromSize*(s: Size, lo: Pt = Pt(x: 0, y: 0)): Rect =
144113 b.fill(NO_CHAR)
145114 return b
146115
147 proc newLayer*(size: Size): Layer =
148 Layer(blit: newBlit(size), invalid: emptyRect())
116 ## ITERATORS
149117
150 proc newLayer*(blit: Blit): Layer =
151 Layer(blit: blit, invalid: emptyRect())
152
153 proc newComp*(size: Size): Comp =
154 Comp(size: size,
155 tb: newTerminalBuffer(size.w, size.h),
156 layers: newSeq[Layer](),
157 fullrepaint: true,
158 srclayer: newRectBuf[int](size))
159
160 ## PAINTING
161
162 iterator pointsinside(rects: seq[Rect]): Pt =
118 iterator pointsInside*(rects: seq[Rect]): Pt =
163119 var domain = emptyRect()
164120 for r in rects:
165121 domain += r
170126 if r.contains(p):
171127 yield p
172128 break
173
174 proc paint*(c: Comp) =
175 c.tb.clear()
176 for layer in c.layers:
177 for point in pointsinside(@[layer.dst]):
178 c.tb.write(point.x, point.y, layer.get(point)[0].toUTF8)
179 c.tb.display()
180
181 ## LAYER MANAGEMENT
182
183 proc pushlayer*(c: var Comp, l: Layer) =
184 c.layers.add(l)
185
186 proc poplayer*(c: var Comp) =
187 c.layers.delete(c.layers.len - 1)
188
189 proc `size=`*(c: var Comp, s: Size) =
190 c.tb = newTerminalBuffer(s.w, s.h)
191 c.size = s
192
193 proc translate*(l: var Layer, amt: Pt) =
194 l.src += amt
195
196 proc `dst=`*(l: var Layer, r: Rect) =
197 l.invalid += l.dst
198 l.invalid += r
199 l.dst = r
200
201 ## DEBUG
202
203 proc print*(b: Comp) =
204 for j in 0..(b.size.h - 1):
205 for i in 0..(b.size.w - 1):
206 var c = b.get(newPt(i, j))
207 if c == NO_CHAR:
208 stdout.write(' ')
209 else:
210 stdout.write(c[0].toUTF8)
211 stdout.write('\n')
212
213 proc printsrc*(b: Comp) =
214 for j in 0..(b.size.h - 1):
215 for i in 0..(b.size.w - 1):
216 var c = b.srclayer.get(newPt(i, j))
217 stdout.write(if c == NO_LAYER: 'X' else: char(int('1') + c))
218 stdout.write('\n')
219
220 proc printdebug*(c: Comp) =
221 echo c.layers[0].src, " -> ", c.layers[0].dst
0 import blit
1
2 import bitops
3 import illwill
4 import math
5 import unicode
6
7 type
8 LayoutTag* {.pure.} = enum
9 center, left, right
10
11 Layer* = ref object
12 blit*: Blit
13 src*: Pt
14 dst*: Rect
15 tag*: LayoutTag
16
17 Comp* = ref object
18 size: Size
19 tb: illwill.TerminalBuffer
20 layers: seq[Layer]
21
22 proc size*(l: Layer): Size = l.dst.size()
23 proc size*(c: Comp): Size = c.size
24
25 proc contains*(l: Layer, p: Pt): bool =
26 l.dst.contains(p) and l.blit.contains(p - l.src)
27
28 proc get*(l: Layer, dst: Pt): Char =
29 var src = Pt(
30 x: l.src.x + (dst.x - l.dst.lo.x),
31 y: l.src.y + (dst.y - l.dst.lo.y))
32 if l.blit.contains(src):
33 return l.blit.get(src)
34 return NO_CHAR
35
36 proc get*(c: Comp, p: Pt): TerminalChar =
37 return c.tb[p.x, p.y]
38
39 proc newLayer*(size: Size): Layer =
40 Layer(blit: newBlit(size), tag: LayoutTag.center)
41
42 proc newLayer*(blit: Blit): Layer =
43 Layer(blit: blit, tag: LayoutTag.center)
44
45 proc newComp*(size: Size): Comp =
46 Comp(size: size,
47 tb: newTerminalBuffer(size.w, size.h),
48 layers: newSeq[Layer]())
49
50 proc layout(c: var Comp) =
51 var
52 lcenter: Layer = nil
53 lleft: Layer = nil
54 lright: Layer = nil
55 for layer in c.layers:
56 case layer.tag
57 of center:
58 if lcenter == nil:
59 lcenter = layer
60 of right:
61 if lright == nil:
62 lright = layer
63 of left:
64 if lleft == nil:
65 lleft = layer
66
67 var present = 0
68 let full = rectFromSize(c.size)
69 if lleft != nil:
70 present = bitor(present, 0b100)
71 lleft.dst = full
72 if lcenter != nil:
73 present = bitor(present, 0b010)
74 lcenter.dst = full
75 if lright != nil:
76 present = bitor(present, 0b001)
77 lright.dst = full
78
79 case present
80 of 0b010, 0b100, 0b001: discard
81 of 0b110:
82 let split = int(ceil(c.size.w.float * 0.33))
83 lleft.dst.hi.x = split - 1
84 lcenter.dst.lo.x = split
85 of 0b011:
86 let split = int(ceil(c.size.w.float * 0.67))
87 lcenter.dst.hi.x = split - 1
88 lright.dst.lo.x = split
89 of 0b101:
90 let split = int(c.size.w.float * 0.5)
91 lleft.dst.hi.x = split - 1
92 lright.dst.lo.x = split
93 of 0b111:
94 let lsplit = int(ceil(c.size.w.float * 0.25))
95 let rsplit = int(ceil(c.size.w.float * 0.75))
96 lleft.dst.hi.x = lsplit - 1
97 lcenter.dst.lo.x = lsplit
98 lcenter.dst.hi.x = rsplit - 1
99 lright.dst.lo.x = rsplit
100 else: discard
101
102 proc paint*(c: var Comp) =
103 c.layout()
104 c.tb.clear()
105 for layer in c.layers:
106 for point in pointsInside(@[layer.dst]):
107 c.tb.write(point.x, point.y, layer.get(point)[0].toUTF8)
108 c.tb.display()
109
110 proc pushlayer*(c: var Comp, l: Layer) =
111 c.layers.add(l)
112
113 proc poplayer*(c: var Comp) =
114 c.layers.delete(c.layers.len - 1)
115
116 proc `size=`*(c: var Comp, s: Size) =
117 c.tb = newTerminalBuffer(s.w, s.h)
118 c.size = s
119
120 proc print*(b: Comp) =
121 for j in 0..(b.size.h - 1):
122 for i in 0..(b.size.w - 1):
123 var c = b.get(newPt(i, j))
124 stdout.write(c.ch.toUTF8)
125 stdout.write('\n')
126
127 proc printdebug*(c: Comp) =
128 echo c.layers[0].src, " -> ", c.layers[0].dst
+19
-12
e.nim less more
0 import blit, buf
0 import blit, buf, comp
11 import illwill
22 import os, system
33
4 var comp = blit.newComp(Size(w: 30, h: 20))
4 var c = newComp(Size(w: 30, h: 20))
55
66 var bx = newBuf()
77 bx.load("test/pg844.txt")
88
9 var lx = blit.newLayer(bx.blit)
10 lx.dst = rectFromSize(comp.size())
11 comp.pushlayer(lx)
9 var lx = newLayer(bx.blit)
10 c.pushlayer(lx)
11
12 var ly = newLayer(bx.blit)
13 ly.tag = LayoutTag.left
14 c.pushlayer(ly)
15
16 var lz = newLayer(bx.blit)
17 lz.tag = LayoutTag.right
18 c.pushlayer(lz)
1219
1320 proc exitProc() {.noconv.} =
1421 illwillDeinit()
2936 try:
3037 while true:
3138 var size = Size(w: terminalWidth(), h: terminalHeight())
32 if size != comp.size:
33 comp.size = size
39 if size != c.size:
40 c.size = size
3441
3542 var k = illwill.getKey()
3643 case k
3744 of Key.Escape, Key.Q:
3845 exitProc()
3946 of Key.J:
40 lx.translate(newPt(0, 1))
47 lx.src.y += 1
4148 of Key.K:
42 lx.translate(newPt(0, -1))
49 lx.src.y -= 1
4350 of Key.H:
44 lx.translate(newPt(-1, 0))
51 lx.src.x += 1
4552 of Key.L:
46 lx.translate(newPt(1, 0))
53 lx.src.x -= 1
4754 of Key.None:
4855 discard
4956 else:
5057 discard
5158
52 comp.paint()
59 c.paint()
5360 sleep(16)
5461 except:
5562 exitProc()