danaugrs před 7 roky
rodič
revize
effc652436
2 změnil soubory, kde provedl 109 přidání a 83 odebrání
  1. 9 2
      gui/label.go
  2. 100 81
      text/font.go

+ 9 - 2
gui/label.go

@@ -11,8 +11,8 @@ import (
 	"github.com/g3n/engine/texture"
 )
 
-// Label is a panel which contains a texture for rendering text
-// The content size of the label panel is the exact size of texture
+// Label is a panel which contains a texture for rendering text.
+// The content size of the label panel is the exact size of the texture.
 type Label struct {
 	Panel       // Embedded panel
 	fontSize    float64
@@ -28,6 +28,7 @@ type Label struct {
 // NewLabel creates and returns a label panel with the specified text
 // drawn using the current default text font.
 // If icon is true the text is drawn using the default icon font
+// TODO allow passing in any font
 func NewLabel(msg string, icon ...bool) *Label {
 
 	l := new(Label)
@@ -45,6 +46,12 @@ func (l *Label) initialize(msg string, font *text.Font) {
 
 	l.font = font
 	l.Panel.Initialize(0, 0)
+
+	// TODO: Remove this hack in an elegant way
+	if font != StyleDefault().FontIcon {
+		l.Panel.SetPaddings(2, 0, 2, 0)
+	}
+
 	l.fontSize = 14
 	l.fontDPI = 72
 	l.lineSpacing = 1.0

+ 100 - 81
text/font.go

@@ -13,11 +13,10 @@ import (
 	"image/color"
 	"image/draw"
 	"io/ioutil"
-	"math"
 	"strings"
 )
 
-// Font represents a TrueType font
+// Font represents a TrueType font face.
 type Font struct {
 	ttf         *truetype.Font
 	face        font.Face
@@ -25,22 +24,21 @@ type Font struct {
 	bgColor     math32.Color4
 	fontSize    float64
 	fontDPI     float64
-	lineSpacing float64
+	lineSpacing float64 // [0,1] relative to font height
 	fg          *image.Uniform
 	bg          *image.Uniform
 	hinting     font.Hinting
 	changed     bool
 }
 
-// Font hinting types
+// Font hinting types.
 const (
 	HintingNone     = font.HintingNone
 	HintingVertical = font.HintingVertical
 	HintingFull     = font.HintingFull
 )
 
-// NewFont creates and returns a new font object using the specified
-// truetype font file
+// NewFont creates and returns a new font object using the specified TrueType font file.
 func NewFont(fontfile string) (*Font, error) {
 
 	// Reads font bytes
@@ -51,18 +49,17 @@ func NewFont(fontfile string) (*Font, error) {
 	return NewFontFromData(fontBytes)
 }
 
-// NewFontFromData creates and returns a new font object from the
-// specified data
+// NewFontFromData creates and returns a new font object from the specified data.
 func NewFontFromData(fontData []byte) (*Font, error) {
 
 	// Parses the font data
-	ff, err := truetype.Parse(fontData)
+	ttf, err := truetype.Parse(fontData)
 	if err != nil {
 		return nil, err
 	}
 
 	f := new(Font)
-	f.ttf = ff
+	f.ttf = ttf
 	f.fontSize = 12
 	f.fontDPI = 72
 	f.lineSpacing = 1.0
@@ -80,27 +77,51 @@ func NewFontFromData(fontData []byte) (*Font, error) {
 	return f, nil
 }
 
-// SetDPI sets the current DPI for the font
-func (f *Font) SetDPI(dpi float64) {
+// SetSize sets the size of the font.
+func (f *Font) SetSize(size float64) {
 
-	if dpi == f.fontDPI {
+	if size == f.fontSize {
 		return
 	}
-	f.fontDPI = dpi
+	f.fontSize = size
 	f.changed = true
 }
 
-// SetSize sets the size of the font
-func (f *Font) SetSize(size float64) {
+// Size returns the current font size.
+func (f *Font) Size() float64 {
 
-	if size == f.fontSize {
+	return f.fontSize
+}
+
+// SetDPI sets the current DPI of the font.
+func (f *Font) SetDPI(dpi float64) {
+
+	if dpi == f.fontDPI {
 		return
 	}
-	f.fontSize = size
+	f.fontDPI = dpi
 	f.changed = true
 }
 
-// SetHinting sets the hinting type
+// DPI returns the current font DPI.
+func (f *Font) DPI() float64 {
+
+	return f.fontDPI
+}
+
+// SetLineSpacing sets the spacing between lines.
+func (f *Font) SetLineSpacing(spacing float64) {
+
+	f.lineSpacing = spacing
+}
+
+// LineSpacing returns the current spacing between lines.
+func (f *Font) LineSpacing() float64 {
+
+	return f.lineSpacing
+}
+
+// SetHinting sets the hinting type.
 func (f *Font) SetHinting(hinting font.Hinting) {
 
 	if hinting == f.hinting {
@@ -110,96 +131,94 @@ func (f *Font) SetHinting(hinting font.Hinting) {
 	f.changed = true
 }
 
-// Size returns the current font size
-func (f *Font) Size() float64 {
+// Hinting returns the current hinting type.
+func (f *Font) Hinting() font.Hinting {
 
-	return f.fontSize
+	return f.hinting
 }
 
-// DPI returns the current font DPI
-func (f *Font) DPI() float64 {
-
-	return f.fontDPI
-}
-
-// SetFgColor sets the current foreground color of the font
-// The alpha value is set to 1 (opaque)
+// SetFgColor sets the current foreground color of the font.
+// The alpha value is set to 1 (opaque).
 func (f *Font) SetFgColor(color *math32.Color) {
 
-	f.fgColor.R = color.R
-	f.fgColor.G = color.G
-	f.fgColor.B = color.B
-	f.fgColor.A = 1.0
+	f.fgColor.FromColor(color, 1.0)
 	f.fg = image.NewUniform(Color4RGBA(&f.fgColor))
 }
 
-// SetFgColor4 sets the current foreground color of the font
+// SetFgColor4 sets the current foreground color of the font.
 func (f *Font) SetFgColor4(color *math32.Color4) {
 
 	f.fgColor = *color
 	f.fg = image.NewUniform(Color4RGBA(color))
 }
 
-// FgColor4 returns the current foreground color
+// FgColor4 returns the current foreground color.
 func (f *Font) FgColor4() math32.Color4 {
 
 	return f.fgColor
 }
 
-// SetBgColor sets the current foreground color of the font
-// The alpha value is set to 1 (opaque)
+// SetBgColor sets the current foreground color of the font.
+// The alpha value is set to 1 (opaque).
 func (f *Font) SetBgColor(color *math32.Color) {
 
-	f.bgColor.R = color.R
-	f.bgColor.G = color.G
-	f.bgColor.B = color.B
-	f.bgColor.A = 1.0
+	f.bgColor.FromColor(color, 1.0)
 	f.bg = image.NewUniform(Color4RGBA(&f.fgColor))
 }
 
-// SetBgColor4 sets the current background color of the font
+// SetBgColor4 sets the current background color of the font.
 func (f *Font) SetBgColor4(color *math32.Color4) {
 
 	f.bgColor = *color
 	f.bg = image.NewUniform(Color4RGBA(color))
 }
 
-// BgColor4 returns the current background color
+// BgColor4 returns the current background color.
 func (f *Font) BgColor4() math32.Color4 {
 
 	return f.bgColor
 }
 
-// SetLineSpacing sets the spacing between lines
-func (f *Font) SetLineSpacing(spacing float64) {
+// updateFace updates the font face if parameters have changed.
+func (f *Font) updateFace() {
 
-	f.lineSpacing = spacing
+	if f.changed {
+		f.face = truetype.NewFace(f.ttf, &truetype.Options{
+			Size:    f.fontSize,
+			DPI:     f.fontDPI,
+			Hinting: f.hinting,
+		})
+		f.changed = false
+	}
 }
 
-// MeasureText returns the maximum width and height in pixels
+// MeasureText returns the minimum width and height in pixels
 // necessary for an image to contain the specified text.
 // The supplied text string can contain line break escape sequences (\n).
 func (f *Font) MeasureText(text string) (int, int) {
 
-	// Creates drawer
+	// Create font drawer
 	f.updateFace()
 	d := &font.Drawer{Dst: nil, Src: f.fg, Face: f.face}
 
 	// Draw text
-	width := 0
-	py := int(math.Ceil(f.fontSize * f.fontDPI / 72))
-	dy := int(math.Ceil(f.fontSize * f.lineSpacing * f.fontDPI / 72))
+	var width, height int
+	metrics := f.face.Metrics()
+	lineHeight := (metrics.Ascent + metrics.Descent).Ceil()
+	lineGap := int((f.lineSpacing - float64(1)) * float64(lineHeight))
+
 	lines := strings.Split(text, "\n")
-	for _, s := range lines {
-		d.Dot = fixed.P(0, py)
-		lfixed := d.MeasureString(s)
-		lw := int(lfixed >> 6)
-		if lw > width {
-			width = lw
+	for i, s := range lines {
+		d.Dot = fixed.P(0, height)
+		lineWidth := d.MeasureString(s).Ceil()
+		if lineWidth > width {
+			width = lineWidth
+		}
+		height += lineHeight
+		if i > 1 {
+			height += lineGap
 		}
-		py += dy
 	}
-	height := py - dy/2
 	return width, height
 }
 
@@ -216,19 +235,6 @@ type Canvas struct {
 	bgColor *image.Uniform
 }
 
-// Update font face if font parameters changed
-func (f *Font) updateFace() {
-
-	if f.changed {
-		f.face = truetype.NewFace(f.ttf, &truetype.Options{
-			Size:    f.fontSize,
-			DPI:     f.fontDPI,
-			Hinting: f.hinting,
-		})
-		f.changed = false
-	}
-}
-
 // NewCanvas creates and returns a pointer to a new canvas with the
 // specified width and height in pixels and background color
 func NewCanvas(width, height int, bgColor *math32.Color4) *Canvas {
@@ -254,13 +260,18 @@ func (c Canvas) DrawText(x, y int, text string, f *Font) {
 	d := &font.Drawer{Dst: c.RGBA, Src: f.fg, Face: f.face}
 
 	// Draw text
-	py := y + int(math.Ceil(f.fontSize*f.fontDPI/72))
-	dy := int(math.Ceil(f.fontSize * f.lineSpacing * f.fontDPI / 72))
+	metrics := f.face.Metrics()
+	py := y + metrics.Ascent.Round()
+	lineHeight := (metrics.Ascent + metrics.Descent).Ceil()
+	lineGap := int((f.lineSpacing - float64(1)) * float64(lineHeight))
 	lines := strings.Split(text, "\n")
-	for _, s := range lines {
+	for i, s := range lines {
 		d.Dot = fixed.P(x, py)
 		d.DrawString(s)
-		py += dy
+		py += lineHeight
+		if i > 1 {
+			py += lineGap
+		}
 	}
 }
 
@@ -274,8 +285,11 @@ func (c Canvas) DrawTextCaret(x, y int, text string, f *Font, line, col int) err
 	f.updateFace()
 	d := &font.Drawer{Dst: c.RGBA, Src: f.fg, Face: f.face}
 
-	py := y + int(math.Ceil(f.fontSize*f.fontDPI/72))
-	dy := int(math.Ceil(f.fontSize * f.lineSpacing * f.fontDPI / 72))
+	// Draw text
+	metrics := f.face.Metrics()
+	py := y + metrics.Ascent.Round()
+	lineHeight := (metrics.Ascent + metrics.Descent).Ceil()
+	lineGap := int((f.lineSpacing - float64(1)) * float64(lineHeight))
 	lines := strings.Split(text, "\n")
 	for l, s := range lines {
 		d.Dot = fixed.P(x, py)
@@ -287,13 +301,18 @@ func (c Canvas) DrawTextCaret(x, y int, text string, f *Font, line, col int) err
 			caretH := int(f.fontSize) + 2
 			//caretY := int(pt.Y>>6) - int(f.fontSize) + 2
 			caretY := int(d.Dot.Y>>6) - int(f.fontSize) + 2
-			color := Color4RGBA(&math32.Color4{0, 0, 0, 1})
+			fgCol := f.FgColor4()
+			color := Color4RGBA(&fgCol)
 			for j := caretY; j < caretY+caretH; j++ {
 				c.RGBA.Set(x+width, j, color)
 			}
 		}
-		py += dy
+		py += lineHeight
+		if l > 1 {
+			py += lineGap
+		}
 	}
+
 	//	pt := freetype.Pt(font.marginX+x, font.marginY+y+int(font.ctx.PointToFixed(font.fontSize)>>6))
 	//	for l, s := range lines {
 	//		// Draw string