9fans.net/go@v0.0.5/draw/frame/frdraw.go (about) 1 package frame 2 3 import ( 4 "fmt" 5 6 "9fans.net/go/draw" 7 ) 8 9 func (f *Frame) drawtext(pt draw.Point, text, back *draw.Image) { 10 for nb := 0; nb < len(f.box); nb++ { 11 b := &f.box[nb] 12 f.cklinewrap(&pt, b) 13 if f.NoRedraw == 0 && b.nrune >= 0 { 14 f.B.BytesBg(pt, text, draw.Point{}, f.Font, b.bytes, back, draw.Point{}) 15 } 16 pt.X += b.wid 17 } 18 } 19 20 // Drawsel repaints a section of the frame, 21 // delimited by character positions p0 and p1, either with 22 // plain background or entirely highlighted, according to the 23 // flag highlighted, managing the tick appropriately. 24 // 25 // The point pt0 is the geometrical location of p0 on the screen; 26 // like all of the selection-helper routines' Point arguments, 27 // it must be a value generated by PointOf. 28 func (f *Frame) Drawsel(pt0 draw.Point, p0, p1 int, highlighted bool) { 29 if f.Ticked { 30 f.Tick(f.PointOf(f.P0), false) 31 } 32 if p0 == p1 { 33 f.Tick(pt0, highlighted) 34 return 35 } 36 37 back, text := f.Cols[BACK], f.Cols[TEXT] 38 if highlighted { 39 back, text = f.Cols[HIGH], f.Cols[HTEXT] 40 } 41 f.Drawsel0(pt0, p0, p1, back, text) 42 } 43 44 // Drawsel0 is a lower-level Drawsel, taking as arguments a background color, 45 // back, and text color, text. It assumes that the tick is 46 // being handled (removed beforehand, replaced afterwards, as 47 // required) by its caller. 48 func (f *Frame) Drawsel0(pt draw.Point, p0, p1 int, back, text *draw.Image) draw.Point { 49 if p0 > p1 { 50 panic(fmt.Sprintf("libframe: frDrawsel0 p0=%d > p1=%d", p0, p1)) 51 } 52 53 p := 0 54 trim := 0 55 nb := 0 56 for ; nb < len(f.box) && p < p1; nb++ { 57 b := &f.box[nb] 58 nr := b.nrune 59 if nr < 0 { 60 nr = 1 61 } 62 if p+nr <= p0 { 63 p += nr 64 continue 65 } 66 if p >= p0 { 67 qt := pt 68 f.cklinewrap(&pt, b) 69 // fill in the end of a wrapped line 70 if pt.Y > qt.Y { 71 f.B.Draw(draw.Rect(qt.X, qt.Y, f.R.Max.X, pt.Y), back, nil, qt) 72 } 73 } 74 ptr := b.bytes 75 if p < p0 { // beginning of region: advance into box 76 ptr = ptr[runeindex(ptr, p0-p):] 77 nr -= p0 - p 78 p = p0 79 } 80 trim = 0 81 if p+nr > p1 { // end of region: trim box 82 nr -= (p + nr) - p1 83 trim = 1 84 } 85 var w int 86 if b.nrune < 0 || nr == b.nrune { 87 w = b.wid 88 } else { 89 ptr = ptr[:runeindex(ptr, nr)] 90 w = f.Font.BytesWidth(ptr) 91 } 92 x := pt.X + w 93 if x > f.R.Max.X { 94 x = f.R.Max.X 95 } 96 f.B.Draw(draw.Rect(pt.X, pt.Y, x, pt.Y+f.Font.Height), back, nil, pt) 97 if b.nrune >= 0 { 98 f.B.BytesBg(pt, text, draw.Point{}, f.Font, ptr, back, draw.Point{}) 99 } 100 pt.X += w 101 p += nr 102 } 103 104 // if this is end of last plain text box on wrapped line, fill to end of line 105 if p1 > p0 && 0 < nb && nb < len(f.box) && f.box[nb-1].nrune > 0 && trim == 0 { 106 qt := pt 107 b := &f.box[nb] 108 f.cklinewrap(&pt, b) 109 if pt.Y > qt.Y { 110 f.B.Draw(draw.Rect(qt.X, qt.Y, f.R.Max.X, pt.Y), back, nil, qt) 111 } 112 } 113 return pt 114 } 115 116 func (f *Frame) Redraw() { 117 if f.P0 == f.P1 { 118 ticked := f.Ticked 119 if ticked { 120 f.Tick(f.PointOf(f.P0), false) 121 } 122 f.Drawsel0(f.PointOf(0), 0, f.NumChars, f.Cols[BACK], f.Cols[TEXT]) 123 if ticked { 124 f.Tick(f.PointOf(f.P0), true) 125 } 126 return 127 } 128 129 pt := f.PointOf(0) 130 pt = f.Drawsel0(pt, 0, f.P0, f.Cols[BACK], f.Cols[TEXT]) 131 pt = f.Drawsel0(pt, f.P0, f.P1, f.Cols[HIGH], f.Cols[HTEXT]) 132 pt = f.Drawsel0(pt, f.P1, f.NumChars, f.Cols[BACK], f.Cols[TEXT]) 133 _ = pt 134 } 135 136 // Tick draws (if ticked is true) or 137 // removes (if ticked is false) the tick at the screen position 138 // indicated by pt. 139 func (f *Frame) Tick(pt draw.Point, ticked bool) { 140 if f.tickscale != f.Display.ScaleSize(1) { 141 if f.Ticked { 142 f.drawTick(pt, false) 143 } 144 f.InitTick() 145 } 146 f.drawTick(pt, ticked) 147 } 148 149 func (f *Frame) drawTick(pt draw.Point, ticked bool) { 150 if f.Ticked == ticked || f.tick == nil && !pt.In(f.R) { 151 return 152 } 153 pt.X -= f.tickscale // looks best just left of where requested 154 r := draw.Rect(pt.X, pt.Y, pt.X+_FRTICKW*f.tickscale, pt.Y+f.Font.Height) 155 // can go into left border but not right 156 if r.Max.X > f.R.Max.X { 157 r.Max.X = f.R.Max.X 158 } 159 if ticked { 160 f.tickback.Draw(f.tickback.R, f.B, nil, pt) 161 f.B.Draw(r, f.tick, nil, draw.ZP) 162 } else { 163 f.B.Draw(r, f.tickback, nil, draw.ZP) 164 } 165 f.Ticked = ticked 166 } 167 168 func (f *Frame) draw(pt draw.Point) draw.Point { 169 for nb := 0; nb < len(f.box); nb++ { 170 b := &f.box[nb] 171 f.cklinewrap0(&pt, b) 172 if pt.Y == f.R.Max.Y { 173 f.NumChars -= f.strlen(nb) 174 f.delbox(nb, len(f.box)-1) 175 break 176 } 177 if b.nrune > 0 { 178 n := f.canfit(pt, b) 179 if n == 0 { 180 break 181 } 182 if n != b.nrune { 183 f.splitbox(nb, n) 184 b = &f.box[nb] 185 } 186 pt.X += b.wid 187 } else { 188 if b.bc == '\n' { 189 pt.X = f.R.Min.X 190 pt.Y += f.Font.Height 191 } else { 192 pt.X += f.newwid(pt, b) 193 } 194 } 195 } 196 return pt 197 } 198 199 func (f *Frame) strlen(nb int) int { 200 n := 0 201 for ; nb < len(f.box); nb++ { 202 b := &f.box[nb] 203 n += b.NRUNE() 204 } 205 return n 206 }