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  }