-
Notifications
You must be signed in to change notification settings - Fork 26
/
tagline.go
110 lines (97 loc) · 2.67 KB
/
tagline.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package renderer
import (
"bytes"
"image"
"image/color"
"image/draw"
"github.com/driusan/de/demodel"
"golang.org/x/image/font"
"golang.org/x/image/math/fixed"
)
// TaglineRenderer is like the default renderer which doesn't
// provide syntax highlighting, but uses a different background
// colour which doesn't change regardless of mode.
type TaglineRenderer struct {
DefaultSizeCalcer
DefaultImageMapper
}
func (r *TaglineRenderer) InvalidateCache() {
r.DefaultSizeCalcer.InvalidateCache()
r.DefaultImageMapper.InvalidateCache()
}
func (r TaglineRenderer) CanRender(*demodel.CharBuffer) bool {
return false
}
func (r TaglineRenderer) RenderInto(dst draw.Image, buf *demodel.CharBuffer, viewport image.Rectangle) error {
dstSize := r.Bounds(buf)
if wSize := viewport.Size().X; dstSize.Max.X < wSize {
dstSize.Max.X = wSize
}
draw.Draw(dst, dst.Bounds(), &image.Uniform{TaglineBackground}, image.ZP, draw.Src)
draw.Draw(dst,
image.Rectangle{
Min: image.Point{0, dstSize.Max.Y - 1},
Max: image.Point{dstSize.Max.X, dstSize.Max.Y},
},
&image.Uniform{color.Black},
image.ZP,
draw.Src,
)
writer := font.Drawer{
Dst: dst,
Src: &image.Uniform{color.Black},
Face: MonoFontFace,
Dot: fixed.P(0, MonoFontAscent.Floor()),
}
runes := bytes.Runes(buf.Buffer)
for i, r := range runes {
runeRectangle := image.Rectangle{}
runeRectangle.Min.X = writer.Dot.X.Ceil()
runeRectangle.Min.Y = writer.Dot.Y.Ceil() - MonoFontAscent.Floor()
switch r {
case '\t':
runeRectangle.Max.X = runeRectangle.Min.X + 8*MonoFontGlyphWidth.Ceil()
case '\n':
runeRectangle.Max.X = dstSize.Max.X
default:
runeRectangle.Max.X = runeRectangle.Min.X + MonoFontGlyphWidth.Ceil()
}
runeRectangle.Max.Y = runeRectangle.Min.Y + MonoFontHeight.Ceil()
if buf.Dot.Start != buf.Dot.End && uint(i) >= buf.Dot.Start && uint(i) <= buf.Dot.End {
writer.Src = &image.Uniform{color.Black}
draw.Draw(
dst,
runeRectangle,
&image.Uniform{TextHighlight},
image.ZP,
draw.Over,
)
} else {
if buf.Dot.Start == buf.Dot.End && buf.Dot.Start == uint(i) {
// draw a cursor at the current location.
draw.Draw(dst,
image.Rectangle{
image.Point{runeRectangle.Min.X, runeRectangle.Min.Y},
image.Point{runeRectangle.Min.X + 1, runeRectangle.Max.Y},
},
&image.Uniform{color.Black},
image.ZP,
draw.Over,
)
}
// it's not within dot, so use a black font on no background.
writer.Src = &image.Uniform{color.Black}
}
switch r {
case '\t':
writer.Dot.X += MonoFontGlyphWidth * 8
continue
case '\n':
writer.Dot.Y += MonoFontHeight
writer.Dot.X = 0
continue
}
writer.DrawString(string(r))
}
return nil
}