github.com/jmigpin/editor@v1.6.0/util/drawutil/drawer4/runereader.go (about)

     1  package drawer4
     2  
     3  import (
     4  	"image"
     5  	"io"
     6  
     7  	"github.com/jmigpin/editor/util/iout/iorw"
     8  	"github.com/jmigpin/editor/util/mathutil"
     9  )
    10  
    11  type RuneReader struct {
    12  	d *Drawer
    13  }
    14  
    15  func (rr *RuneReader) Init() {
    16  	rr.d.st.runeR.fface = rr.d.fface
    17  	rr.d.st.runeR.pen = rr.startingPen()
    18  	rr.d.st.runeR.startRi = -1
    19  }
    20  
    21  func (rr *RuneReader) Iter() {
    22  	// initialize start ri
    23  	if rr.d.st.runeR.startRi == -1 {
    24  		rr.d.st.runeR.startRi = rr.d.st.runeR.ri
    25  	}
    26  
    27  	ru, size, err := iorw.ReadRuneAt(rr.d.reader, rr.d.st.runeR.ri)
    28  	if err != nil {
    29  		// run last advanced position (draw/delayeddraw/selecting)
    30  		if err == io.EOF {
    31  			_ = rr.iter2(eofRune, 0)
    32  		}
    33  		rr.d.iterStop()
    34  		return
    35  	}
    36  	_ = rr.iter2(ru, size)
    37  }
    38  
    39  func (rr *RuneReader) End() {}
    40  
    41  //----------
    42  
    43  func (rr *RuneReader) eof() bool {
    44  	return rr.isNormal() && rr.d.st.runeR.ru == 0
    45  }
    46  
    47  func (rr *RuneReader) iter2(ru rune, size int) bool {
    48  	st := &rr.d.st.runeR
    49  	st.ru = ru
    50  
    51  	// add/subtract kern with previous rune
    52  	k := rr.d.st.runeR.fface.Face.Kern(st.prevRu, st.ru)
    53  	st.kern = mathutil.Intf2(k)
    54  	st.pen.X += st.kern
    55  
    56  	st.advance = rr.tabbedGlyphAdvance(st.ru)
    57  
    58  	if !rr.d.iterNext() {
    59  		return false
    60  	}
    61  
    62  	// advance for next rune
    63  	st.ri += size
    64  	st.prevRu = st.ru
    65  	st.pen.X += st.advance
    66  
    67  	return true
    68  }
    69  
    70  //----------
    71  
    72  func (rr *RuneReader) insertExtraString(s string) bool {
    73  	rr.pushExtra()
    74  	defer rr.popExtra()
    75  
    76  	for _, ru := range s {
    77  		if !rr.iter2(ru, len(string(ru))) {
    78  			return false
    79  		}
    80  	}
    81  	return true
    82  }
    83  
    84  //----------
    85  
    86  func (rr *RuneReader) pushExtra() {
    87  	rr.d.st.runeR.extra++
    88  }
    89  func (rr *RuneReader) popExtra() {
    90  	rr.d.st.runeR.extra--
    91  }
    92  func (rr *RuneReader) isExtra() bool {
    93  	return rr.d.st.runeR.extra > 0
    94  }
    95  func (rr *RuneReader) isNormal() bool {
    96  	return !rr.isExtra()
    97  }
    98  
    99  //----------
   100  
   101  func (rr *RuneReader) glyphAdvance(ru rune) mathutil.Intf {
   102  	adv, ok := rr.d.st.runeR.fface.Face.GlyphAdvance(ru)
   103  	if !ok {
   104  		return 0
   105  	}
   106  	return mathutil.Intf2(adv)
   107  }
   108  
   109  func (rr *RuneReader) tabbedGlyphAdvance(ru rune) mathutil.Intf {
   110  	adv := rr.glyphAdvance(ru)
   111  	if ru == '\t' {
   112  		adv = rr.nextTabStopAdvance(rr.d.st.runeR.pen.X, adv)
   113  	}
   114  	return adv
   115  }
   116  
   117  func (rr *RuneReader) nextTabStopAdvance(penx, tadv mathutil.Intf) mathutil.Intf {
   118  	px := penx - rr.startingPen().X
   119  	x := px + tadv
   120  	n := int(x / tadv)
   121  	nadv := mathutil.Intf(n) * tadv
   122  	return nadv - px
   123  }
   124  
   125  //----------
   126  
   127  func (rr *RuneReader) penBounds() mathutil.RectangleIntf {
   128  	st := &rr.d.st.runeR
   129  	minX, minY := st.pen.X, st.pen.Y
   130  	maxX, maxY := minX+st.advance, minY+rr.d.lineHeight
   131  	min := mathutil.PointIntf{minX, minY}
   132  	max := mathutil.PointIntf{maxX, maxY}
   133  	return mathutil.RectangleIntf{min, max}
   134  }
   135  
   136  func (rr *RuneReader) penBoundsRect() image.Rectangle {
   137  	pb := rr.penBounds()
   138  	// expand min (use floor), and max (use ceil)
   139  	return pb.ToRectFloorCeil()
   140  }
   141  
   142  //----------
   143  
   144  func (rr *RuneReader) startingPen() mathutil.PointIntf {
   145  	p := rr.d.bounds.Min
   146  	p.X += rr.d.Opt.RuneReader.StartOffsetX
   147  	if rr.d.st.runeR.ri == 0 {
   148  		p.X += rr.d.firstLineOffsetX
   149  	}
   150  	return mathutil.PIntf2(p)
   151  }
   152  
   153  func (rr *RuneReader) maxX() mathutil.Intf {
   154  	return mathutil.Intf1(rr.d.bounds.Max.X)
   155  }
   156  
   157  //----------
   158  
   159  type runeType int
   160  
   161  const (
   162  	rtNormal runeType = iota
   163  	rtBackground
   164  	rtInserted
   165  	//rtAnnotation
   166  )