9fans.net/go@v0.0.5/draw/frame/frptofchar.go (about) 1 package frame 2 3 import ( 4 "unicode/utf8" 5 6 "9fans.net/go/draw" 7 ) 8 9 func (f *Frame) ptofcharptb(p int, pt draw.Point, bn int) draw.Point { 10 for ; bn < len(f.box); bn++ { 11 b := &f.box[bn] 12 f.cklinewrap(&pt, b) 13 l := b.NRUNE() 14 if p < l { 15 if b.nrune > 0 { 16 s := b.bytes 17 for ; p > 0; p-- { 18 if len(s) == 0 { 19 drawerror(f.Display, "frptofchar") 20 } 21 _, size := utf8.DecodeRune(s) 22 pt.X += f.Font.BytesWidth(s[:size]) 23 s = s[size:] 24 if pt.X > f.R.Max.X { 25 drawerror(f.Display, "frptofchar") 26 } 27 } 28 } 29 break 30 } 31 p -= l 32 f.advance(&pt, b) 33 } 34 return pt 35 } 36 37 // PointOf returns 38 // the location of the upper left corner of the p'th rune, 39 // starting from 0, in the Frame f. If f holds fewer than p 40 // runes, frptofchar returns the location of the upper right 41 // corner of the last character in f. 42 func (f *Frame) PointOf(p int) draw.Point { 43 return f.ptofcharptb(p, f.R.Min, 0) 44 } 45 46 func (f *Frame) ptofcharnb(p, nb int) draw.Point { 47 // doesn't do final f.advance to next line 48 box := f.box 49 f.box = f.box[:nb] 50 pt := f.ptofcharptb(p, f.R.Min, 0) 51 f.box = box 52 return pt 53 } 54 55 func (f *Frame) grid(p draw.Point) draw.Point { 56 p.Y -= f.R.Min.Y 57 p.Y -= p.Y % f.Font.Height 58 p.Y += f.R.Min.Y 59 if p.X > f.R.Max.X { 60 p.X = f.R.Max.X 61 } 62 return p 63 } 64 65 // CharOf is the 66 // inverse of PointOf: it returns the index of the closest rune whose 67 // image's upper left corner is up and to the left of pt. 68 func (f *Frame) CharOf(pt draw.Point) int { 69 pt = f.grid(pt) 70 qt := f.R.Min 71 p := 0 72 bn := 0 73 for ; bn < len(f.box) && qt.Y < pt.Y; bn++ { 74 b := &f.box[bn] 75 f.cklinewrap(&qt, b) 76 if qt.Y >= pt.Y { 77 break 78 } 79 f.advance(&qt, b) 80 p += b.NRUNE() 81 } 82 for ; bn < len(f.box) && qt.X <= pt.X; bn++ { 83 b := &f.box[bn] 84 f.cklinewrap(&qt, b) 85 if qt.Y > pt.Y { 86 break 87 } 88 if qt.X+b.wid > pt.X { 89 if b.nrune < 0 { 90 f.advance(&qt, b) 91 } else { 92 s := b.bytes 93 for { 94 if len(s) == 0 { 95 drawerror(f.Display, "end of string in frcharofpt") 96 } 97 _, size := utf8.DecodeRune(s) 98 qt.X += f.Font.BytesWidth(s[:size]) 99 s = s[size:] 100 if qt.X > pt.X { 101 break 102 } 103 p++ 104 } 105 } 106 } else { 107 p += b.NRUNE() 108 f.advance(&qt, b) 109 } 110 } 111 return p 112 }