aboutsummaryrefslogtreecommitdiffstats
path: root/gui/text/text.go
blob: 7dc49285cb788a938e42f0a8bd48f6cb9ee0c738 (plain) (blame)
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
package text

import (
	"log"
	"sync"

	"image"
	"image/color"
	"image/draw"

	"golang.org/x/image/font"
	"golang.org/x/image/font/gofont/goregular"
	"golang.org/x/image/font/opentype"
	"golang.org/x/image/math/fixed"
)

var (
	FONT      = goregular.TTF
	FONT_SIZE = 15
	DPI       = 72
	PAD       = 3
)

var face *concurrentFace

func init() {
	fnt, err := opentype.Parse(FONT)
	if err != nil {
		log.Fatal(err)
	}
	fce, err := opentype.NewFace(fnt, &opentype.FaceOptions{
		Size: float64(FONT_SIZE),
		DPI:  float64(DPI),
	})
	if err != nil {
		log.Fatal(err)
	}
	face = &concurrentFace{sync.Mutex{}, fce}
}

type Align int

const (
	ALIGN_LEFT Align = iota
	ALIGN_RIGHT
)

func Size(text string) image.Point {
	bounds := textBounds(text, font.Drawer{Face: face})
	return image.Point{bounds.Max.X - bounds.Min.X + 2*PAD, bounds.Max.Y - bounds.Min.Y + 2*PAD}
}

func Draw(text string, dst draw.Image, r image.Rectangle, fg, bg color.Color, align Align) {
	drawer := font.Drawer{
		Src:  &image.Uniform{fg},
		Face: face,
		Dot:  fixed.P(0, 0),
	}

	// background
	draw.Draw(dst, r, &image.Uniform{bg}, image.ZP, draw.Src)

	// text image
	bounds := textBounds(text, drawer)
	textImg := image.NewRGBA(bounds)
	draw.Draw(textImg, bounds, &image.Uniform{bg}, image.ZP, draw.Src)
	drawer.Dst = textImg
	drawer.DrawString(text)

	leftCentre := image.Pt(bounds.Min.X, (bounds.Min.Y+bounds.Max.Y)/2)
	var target image.Point
	switch align {
	case ALIGN_LEFT:
		target = image.Pt(r.Min.X+PAD, (r.Min.Y+r.Max.Y)/2)
	case ALIGN_RIGHT:
		target = image.Pt(r.Max.X-bounds.Max.X-PAD, (r.Min.Y+r.Max.Y)/2)
	}
	delta := target.Sub(leftCentre)
	draw.Draw(dst, bounds.Add(delta).Intersect(r), textImg, bounds.Min, draw.Src)
}

func textBounds(text string, drawer font.Drawer) image.Rectangle {
	b, _ := drawer.BoundString(text)
	return image.Rect(
		b.Min.X.Floor(),
		b.Min.Y.Floor(),
		b.Max.X.Ceil(),
		b.Max.Y.Ceil(),
	)
}