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  }