9fans.net/go@v0.0.5/draw/frame/frbox.go (about) 1 package frame 2 3 import ( 4 "unicode/utf8" 5 6 "9fans.net/go/draw" 7 ) 8 9 type box struct { 10 wid int // in pixels 11 nrune int // <0 ==> negate and treat as break char 12 bytes []byte 13 bc rune // break char 14 minwid int 15 } 16 17 func drawerror(d *draw.Display, err string) { 18 panic(err) 19 } 20 21 // addbox adds new boxes f.box[bn+1:bn+1+n]. 22 func (f *Frame) addbox(bn, n int) { 23 if bn > len(f.box) { 24 drawerror(f.Display, "addbox") 25 } 26 olen := len(f.box) 27 for cap(f.box) < olen+n { 28 f.box = append(f.box[:cap(f.box)], box{}) 29 } 30 f.box = f.box[:olen+n] 31 copy(f.box[bn+n:], f.box[bn:]) 32 for i := bn; i < bn+n; i++ { 33 f.box[i] = box{} 34 } 35 } 36 37 // delbox deletes boxes f.box[n0:n1+1]. 38 func (f *Frame) delbox(n0, n1 int) { 39 if n0 >= len(f.box) || n1 >= len(f.box) || n1 < n0 { 40 drawerror(f.Display, "delbox") 41 } 42 n1++ 43 copy(f.box[n0:], f.box[n1:]) 44 for j := len(f.box) - (n1 - n0); j < len(f.box); j++ { 45 f.box[j] = box{} 46 } 47 f.box = f.box[:len(f.box)-(n1-n0)] 48 } 49 50 // dupbox duplicates f.box[bn], creating f.box[bn+1]. 51 func (f *Frame) dupbox(bn int) { 52 if f.box[bn].nrune < 0 { 53 drawerror(f.Display, "dupbox") 54 } 55 f.addbox(bn+1, 1) 56 f.box[bn+1] = f.box[bn] 57 if f.box[bn].nrune >= 0 { 58 p := make([]byte, len(f.box[bn].bytes)) 59 copy(p, f.box[bn].bytes) 60 f.box[bn+1].bytes = p 61 } 62 } 63 64 func runeindex(p []byte, n int) int { 65 off := 0 66 for i := 0; i < n; i++ { 67 _, size := utf8.DecodeRune(p[off:]) 68 off += size 69 } 70 return off 71 } 72 73 // truncatebox drops the last n characters from b. 74 func (f *Frame) truncatebox(b *box, n int) { 75 if b.nrune < 0 || b.nrune < n { 76 drawerror(f.Display, "chopbox") 77 } 78 b.nrune -= n 79 b.bytes = b.bytes[:runeindex(b.bytes, b.nrune)] 80 b.wid = f.Font.BytesWidth(b.bytes) 81 } 82 83 // chopbox chops the first n characters from b. 84 func (f *Frame) chopbox(b *box, n int) { 85 if b.nrune < 0 || b.nrune < n { 86 drawerror(f.Display, "chopbox") 87 } 88 i := runeindex(b.bytes, n) 89 copy(b.bytes, b.bytes[i:]) 90 b.bytes = b.bytes[:len(b.bytes)-i] 91 b.nrune -= n 92 b.wid = f.Font.BytesWidth(b.bytes) 93 } 94 95 // splitbox splits box bn after n runes. 96 func (f *Frame) splitbox(bn, n int) { 97 f.dupbox(bn) 98 f.truncatebox(&f.box[bn], f.box[bn].nrune-n) 99 f.chopbox(&f.box[bn+1], n) 100 } 101 102 // mergebox merges boxes bn and bn+1. 103 func (f *Frame) mergebox(bn int) { 104 b0 := &f.box[bn] 105 b1 := &f.box[bn+1] 106 b0.bytes = append(b0.bytes, b1.bytes...) 107 b0.wid += b1.wid 108 b0.nrune += b1.nrune 109 f.delbox(bn+1, bn+1) 110 } 111 112 // findbox returns the index of a box starting at rune offset q, 113 // assuming that box bn starts at rune offset p. 114 // If needed, findbox splits an existing box to make one that 115 // starts at rune offset q. 116 func (f *Frame) findbox(bn, p, q int) int { 117 for bn < len(f.box) && p+f.box[bn].NRUNE() <= q { 118 p += f.box[bn].NRUNE() 119 bn++ 120 } 121 if p != q { 122 f.splitbox(bn, q-p) 123 bn++ 124 } 125 return bn 126 }