소스 검색

improved edit/label/font and panel shader

danaugrs 7 년 전
부모
커밋
3d9211ec5f
18개의 변경된 파일302개의 추가작업 그리고 257개의 파일을 삭제
  1. 1 1
      gui/builder_panel.go
  2. 1 1
      gui/button.go
  3. 1 1
      gui/checkradio.go
  4. 2 2
      gui/dropdown.go
  5. 1 1
      gui/edit.go
  6. 1 1
      gui/folder.go
  7. 1 1
      gui/image_button.go
  8. 2 2
      gui/imagelabel.go
  9. 108 92
      gui/label.go
  10. 2 2
      gui/menu.go
  11. 1 0
      gui/style.go
  12. 12 11
      gui/style_light.go
  13. 3 3
      gui/tabbar.go
  14. 1 1
      gui/table.go
  15. 1 1
      gui/tree.go
  16. 22 3
      renderer/shaders/panel_fragment.glsl
  17. 22 3
      renderer/shaders/sources.go
  18. 120 131
      text/font.go

+ 1 - 1
gui/builder_panel.go

@@ -89,7 +89,7 @@ func buildLabel(b *Builder, am map[string]interface{}) (IPanel, error) {
 
 
 	var label *Label
 	var label *Label
 	if am[AttribIcon] != nil {
 	if am[AttribIcon] != nil {
-		label = NewLabel(am[AttribIcon].(string), true)
+		label = NewIcon(am[AttribIcon].(string))
 	} else if am[AttribText] != nil {
 	} else if am[AttribText] != nil {
 		label = NewLabel(am[AttribText].(string))
 		label = NewLabel(am[AttribText].(string))
 	} else {
 	} else {

+ 1 - 1
gui/button.go

@@ -79,7 +79,7 @@ func NewButton(text string) *Button {
 // If there is currently a selected image, it is removed
 // If there is currently a selected image, it is removed
 func (b *Button) SetIcon(icode string) {
 func (b *Button) SetIcon(icode string) {
 
 
-	ico := NewLabel(icode, true)
+	ico := NewIcon(icode)
 	if b.image != nil {
 	if b.image != nil {
 		b.Panel.Remove(b.image)
 		b.Panel.Remove(b.image)
 		b.image = nil
 		b.image = nil

+ 1 - 1
gui/checkradio.go

@@ -90,7 +90,7 @@ func newCheckRadio(check bool, text string) *CheckRadio {
 	cb.Panel.Add(cb.Label)
 	cb.Panel.Add(cb.Label)
 
 
 	// Creates icon label
 	// Creates icon label
-	cb.icon = NewLabel(" ", true)
+	cb.icon = NewIcon(" ")
 	cb.Panel.Add(cb.icon)
 	cb.Panel.Add(cb.icon)
 
 
 	cb.recalc()
 	cb.recalc()

+ 2 - 2
gui/dropdown.go

@@ -52,8 +52,8 @@ func NewDropDown(width float32, item *ImageLabel) *DropDown {
 	dd.Panel.Add(dd.litem)
 	dd.Panel.Add(dd.litem)
 
 
 	// Create icon
 	// Create icon
-	dd.icon = NewLabel(" ", true)
-	dd.icon.SetFontSize(StyleDefault().Font.Size() * 1.3)
+	dd.icon = NewIcon(" ")
+	dd.icon.SetFontSize(StyleDefault().Label.PointSize * 1.3)
 	dd.icon.SetText(string(icon.ArrowDropDown))
 	dd.icon.SetText(string(icon.ArrowDropDown))
 	dd.Panel.Add(dd.icon)
 	dd.Panel.Add(dd.icon)
 
 

+ 1 - 1
gui/edit.go

@@ -95,7 +95,7 @@ func (ed *Edit) Text() string {
 // SetFontSize sets label font size (overrides Label.SetFontSize)
 // SetFontSize sets label font size (overrides Label.SetFontSize)
 func (ed *Edit) SetFontSize(size float64) *Edit {
 func (ed *Edit) SetFontSize(size float64) *Edit {
 
 
-	ed.Label.fontSize = size
+	ed.Label.SetFontSize(size)
 	ed.redraw(ed.focus)
 	ed.redraw(ed.focus)
 	return ed
 	return ed
 }
 }

+ 1 - 1
gui/folder.go

@@ -56,7 +56,7 @@ func (f *Folder) Initialize(text string, width float32, contentPanel IPanel) {
 
 
 	// Create icon
 	// Create icon
 	f.icon.initialize("", StyleDefault().FontIcon)
 	f.icon.initialize("", StyleDefault().FontIcon)
-	f.icon.SetFontSize(f.label.FontSize() * 1.3)
+	f.icon.SetFontSize(StyleDefault().Label.PointSize * 1.3)
 	f.Panel.Add(&f.icon)
 	f.Panel.Add(&f.icon)
 
 
 	// Setup content panel
 	// Setup content panel

+ 1 - 1
gui/image_button.go

@@ -111,7 +111,7 @@ func (b *ImageButton) SetIcon(icode string) {
 	b.iconLabel = true
 	b.iconLabel = true
 	if b.label == nil {
 	if b.label == nil {
 		// Create icon
 		// Create icon
-		b.label = NewLabel(icode, true)
+		b.label = NewIcon(icode)
 		b.Panel.Add(b.label)
 		b.Panel.Add(b.label)
 	} else {
 	} else {
 		b.label.SetText(icode)
 		b.label.SetText(icode)

+ 2 - 2
gui/imagelabel.go

@@ -72,8 +72,8 @@ func (il *ImageLabel) SetIcon(icon string) {
 		il.image = nil
 		il.image = nil
 	}
 	}
 	if il.icon == nil {
 	if il.icon == nil {
-		il.icon = NewLabel(icon, true)
-		il.icon.SetFontSize(il.label.FontSize() * 1.4)
+		il.icon = NewIcon(icon)
+		il.icon.SetFontSize(StyleDefault().Label.PointSize * 1.4)
 		il.Panel.Add(il.icon)
 		il.Panel.Add(il.icon)
 	}
 	}
 	il.icon.SetText(icon)
 	il.icon.SetText(icon)

+ 108 - 92
gui/label.go

@@ -11,200 +11,216 @@ import (
 	"github.com/g3n/engine/texture"
 	"github.com/g3n/engine/texture"
 )
 )
 
 
-// Label is a panel which contains a texture for rendering text.
+// Label is a panel which contains a texture with text.
 // The content size of the label panel is the exact size of the texture.
 // The content size of the label panel is the exact size of the texture.
 type Label struct {
 type Label struct {
-	Panel       // Embedded panel
-	fontSize    float64
-	fontDPI     float64
-	lineSpacing float64
-	bgColor     math32.Color4
-	fgColor     math32.Color4
-	font        *text.Font
-	tex         *texture.Texture2D // Pointer to texture with drawed text
-	currentText string
-}
-
-// 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 {
+	Panel                    // Embedded Panel
+	font  *text.Font         // TrueType font face
+	tex   *texture.Texture2D // Texture with text
+	style *LabelStyle        // The style of the panel and font attributes
+	text  string             // Text being displayed
+}
+
+// LabelStyle contains all the styling attributes of a Label.
+// It's essentially a BasicStyle combined with FontAttributes.
+type LabelStyle struct {
+	PanelStyle
+	text.FontAttributes
+	FgColor math32.Color4
+}
+
+// NewLabel creates and returns a label panel with
+// the specified text drawn using the default text font.
+func NewLabel(text string) *Label {
+	return NewLabelWithFont(text, StyleDefault().Font)
+}
+
+// NewLabel creates and returns a label panel with
+// the specified text drawn using the default icon font.
+func NewIcon(icon string) *Label {
+	return NewLabelWithFont(icon, StyleDefault().FontIcon)
+}
+
+// NewLabelWithFont creates and returns a label panel with
+// the specified text drawn using the specified font.
+func NewLabelWithFont(msg string, font *text.Font) *Label {
 
 
 	l := new(Label)
 	l := new(Label)
-	if len(icon) > 0 && icon[0] {
-		l.initialize(msg, StyleDefault().FontIcon)
-	} else {
-		l.initialize(msg, StyleDefault().Font)
-	}
+	l.initialize(msg, font)
 	return l
 	return l
 }
 }
 
 
 // initialize initializes this label and is normally used by other
 // initialize initializes this label and is normally used by other
-// gui types which contains a label.
+// components which contain a label.
 func (l *Label) initialize(msg string, font *text.Font) {
 func (l *Label) initialize(msg string, font *text.Font) {
 
 
 	l.font = font
 	l.font = font
 	l.Panel.Initialize(0, 0)
 	l.Panel.Initialize(0, 0)
 
 
-	// TODO: Remove this hack in an elegant way
+	// TODO: Remove this hack in an elegant way e.g. set the label style depending of if it's an icon or text label and have two defaults (one for icon labels one for text tabels)
 	if font != StyleDefault().FontIcon {
 	if font != StyleDefault().FontIcon {
 		l.Panel.SetPaddings(2, 0, 2, 0)
 		l.Panel.SetPaddings(2, 0, 2, 0)
 	}
 	}
 
 
-	l.fontSize = 14
-	l.fontDPI = 72
-	l.lineSpacing = 1.0
-	l.bgColor = math32.Color4{0, 0, 0, 0}
-	l.fgColor = math32.Color4{0, 0, 0, 1}
+	// Copy the style based on the default Label style
+	styleCopy := StyleDefault().Label
+	l.style = &styleCopy
+
 	l.SetText(msg)
 	l.SetText(msg)
 }
 }
 
 
-// SetText draws the label text using the current font
-func (l *Label) SetText(msg string) {
+// SetText sets and draws the label text using the font.
+func (l *Label) SetText(text string) {
 
 
 	// Need at least a character to get dimensions
 	// Need at least a character to get dimensions
-	l.currentText = msg
-	if msg == "" {
-		msg = " "
+	l.text = text
+	if text == "" {
+		text = " "
 	}
 	}
 
 
 	// Set font properties
 	// Set font properties
-	l.font.SetSize(l.fontSize)
-	l.font.SetDPI(l.fontDPI)
-	l.font.SetLineSpacing(l.lineSpacing)
-	l.font.SetBgColor4(&l.bgColor)
-	l.font.SetFgColor4(&l.fgColor)
-
-	// Measure text
-	width, height := l.font.MeasureText(msg)
-	// Create image canvas with the exact size of the texture
-	// and draw the text.
-	canvas := text.NewCanvas(width, height, &l.bgColor)
-	canvas.DrawText(0, 0, msg, l.font)
+	l.font.SetAttributes(&l.style.FontAttributes)
+	l.font.SetColor(&l.style.FgColor)
 
 
-	// Creates texture if if doesnt exist.
+	// Create an image with the text
+	textImage := l.font.DrawText(text)
+
+	// Create texture if it doesn't exist yet
 	if l.tex == nil {
 	if l.tex == nil {
-		l.tex = texture.NewTexture2DFromRGBA(canvas.RGBA)
+		l.tex = texture.NewTexture2DFromRGBA(textImage)
 		l.tex.SetMagFilter(gls.NEAREST)
 		l.tex.SetMagFilter(gls.NEAREST)
 		l.tex.SetMinFilter(gls.NEAREST)
 		l.tex.SetMinFilter(gls.NEAREST)
 		l.Panel.Material().AddTexture(l.tex)
 		l.Panel.Material().AddTexture(l.tex)
 		// Otherwise update texture with new image
 		// Otherwise update texture with new image
 	} else {
 	} else {
-		l.tex.SetFromRGBA(canvas.RGBA)
+		l.tex.SetFromRGBA(textImage)
 	}
 	}
 
 
-	// Updates label panel dimensions
-	l.Panel.SetContentSize(float32(width), float32(height))
+	// Update label panel dimensions
+	l.Panel.SetContentSize(float32(textImage.Rect.Dx()), float32(textImage.Rect.Dy()))
 }
 }
 
 
-// Text returns the current label text
+// Text returns the label text.
 func (l *Label) Text() string {
 func (l *Label) Text() string {
 
 
-	return l.currentText
+	return l.text
 }
 }
 
 
-// SetColor sets the color of the label text
-// The color alpha is set to 1.0
+// SetColor sets the text color.
+// Alpha is set to 1 (opaque).
 func (l *Label) SetColor(color *math32.Color) *Label {
 func (l *Label) SetColor(color *math32.Color) *Label {
 
 
-	l.fgColor.FromColor(color, 1.0)
-	l.SetText(l.currentText)
+	l.style.FgColor.FromColor(color, 1.0)
+	l.SetText(l.text)
 	return l
 	return l
 }
 }
 
 
-// SetColor4 sets the color4 of the label text
+// SetColor4 sets the text color.
 func (l *Label) SetColor4(color4 *math32.Color4) *Label {
 func (l *Label) SetColor4(color4 *math32.Color4) *Label {
 
 
-	l.fgColor = *color4
-	l.SetText(l.currentText)
+	l.style.FgColor = *color4
+	l.SetText(l.text)
 	return l
 	return l
 }
 }
 
 
-// Color returns the current color of the label text
+// Color returns the text color.
 func (l *Label) Color() math32.Color4 {
 func (l *Label) Color() math32.Color4 {
 
 
-	return l.fgColor
+	return l.style.FgColor
 }
 }
 
 
-// SetBgColor sets the color of the label background
+// SetBgColor sets the background color.
 // The color alpha is set to 1.0
 // The color alpha is set to 1.0
 func (l *Label) SetBgColor(color *math32.Color) *Label {
 func (l *Label) SetBgColor(color *math32.Color) *Label {
 
 
-	l.bgColor.FromColor(color, 1.0)
-	l.Panel.SetColor4(&l.bgColor)
-	l.SetText(l.currentText)
+	l.style.BgColor.FromColor(color, 1.0)
+	l.Panel.SetColor4(&l.style.BgColor)
+	l.SetText(l.text)
 	return l
 	return l
 }
 }
 
 
-// SetBgColor4 sets the color4 of the label background
+// SetBgColor4 sets the background color.
 func (l *Label) SetBgColor4(color *math32.Color4) *Label {
 func (l *Label) SetBgColor4(color *math32.Color4) *Label {
 
 
-	l.bgColor = *color
-	l.Panel.SetColor4(&l.bgColor)
-	l.SetText(l.currentText)
+	l.style.BgColor = *color
+	l.Panel.SetColor4(&l.style.BgColor)
+	l.SetText(l.text)
 	return l
 	return l
 }
 }
 
 
-// BgColor returns the current color the label background
+// BgColor returns returns the background color.
 func (l *Label) BgColor() math32.Color4 {
 func (l *Label) BgColor() math32.Color4 {
 
 
-	return l.bgColor
+	return l.style.BgColor
 }
 }
 
 
-// SetFont sets this label text or icon font
+// SetFont sets the font.
 func (l *Label) SetFont(f *text.Font) {
 func (l *Label) SetFont(f *text.Font) {
 
 
 	l.font = f
 	l.font = f
-	l.SetText(l.currentText)
+	l.SetText(l.text)
+}
+
+// Font returns the font.
+func (l *Label) Font() *text.Font {
+
+	return l.font
 }
 }
 
 
-// SetFontSize sets label font size
+// SetFontSize sets the point size of the font.
 func (l *Label) SetFontSize(size float64) *Label {
 func (l *Label) SetFontSize(size float64) *Label {
 
 
-	l.fontSize = size
-	l.SetText(l.currentText)
+	l.style.PointSize = size
+	l.SetText(l.text)
 	return l
 	return l
 }
 }
 
 
-// FontSize returns the current label font size
+// FontSize returns the point size of the font.
 func (l *Label) FontSize() float64 {
 func (l *Label) FontSize() float64 {
 
 
-	return l.fontSize
+	return l.style.PointSize
 }
 }
 
 
-// SetFontDPI sets the font dots per inch
+// SetFontDPI sets the resolution of the font in dots per inch (DPI).
 func (l *Label) SetFontDPI(dpi float64) *Label {
 func (l *Label) SetFontDPI(dpi float64) *Label {
 
 
-	l.fontDPI = dpi
-	l.SetText(l.currentText)
+	l.style.DPI = dpi
+	l.SetText(l.text)
 	return l
 	return l
 }
 }
 
 
+// FontDPI returns the resolution of the font in dots per inch (DPI).
+func (l *Label) FontDPI() float64 {
+
+	return l.style.DPI
+}
+
 // SetLineSpacing sets the spacing between lines.
 // SetLineSpacing sets the spacing between lines.
-// The default value is 1.0
 func (l *Label) SetLineSpacing(spacing float64) *Label {
 func (l *Label) SetLineSpacing(spacing float64) *Label {
 
 
-	l.lineSpacing = spacing
-	l.SetText(l.currentText)
+	l.style.LineSpacing = spacing
+	l.SetText(l.text)
 	return l
 	return l
 }
 }
 
 
+// LineSpacing returns the spacing between lines.
+func (l *Label) LineSpacing() float64 {
+
+	return l.style.LineSpacing
+}
+
 // setTextCaret sets the label text and draws a caret at the
 // setTextCaret sets the label text and draws a caret at the
 // specified line and column.
 // specified line and column.
 // It is normally used by the Edit widget.
 // It is normally used by the Edit widget.
 func (l *Label) setTextCaret(msg string, mx, width, line, col int) {
 func (l *Label) setTextCaret(msg string, mx, width, line, col int) {
 
 
 	// Set font properties
 	// Set font properties
-	l.font.SetSize(l.fontSize)
-	l.font.SetDPI(l.fontDPI)
-	l.font.SetLineSpacing(l.lineSpacing)
-	l.font.SetBgColor4(&l.bgColor)
-	l.font.SetFgColor4(&l.fgColor)
+	l.font.SetAttributes(&l.style.FontAttributes)
+	l.font.SetColor(&l.style.FgColor)
 
 
 	// Create canvas and draw text
 	// Create canvas and draw text
 	_, height := l.font.MeasureText(msg)
 	_, height := l.font.MeasureText(msg)
-	canvas := text.NewCanvas(width, height, &l.bgColor)
+	canvas := text.NewCanvas(width, height, &l.style.BgColor)
 	canvas.DrawTextCaret(mx, 0, msg, l.font, line, col)
 	canvas.DrawTextCaret(mx, 0, msg, l.font, line, col)
 
 
 	// Creates texture if if doesnt exist.
 	// Creates texture if if doesnt exist.
@@ -221,5 +237,5 @@ func (l *Label) setTextCaret(msg string, mx, width, line, col int) {
 
 
 	// Updates label panel dimensions
 	// Updates label panel dimensions
 	l.Panel.SetContentSize(float32(width), float32(height))
 	l.Panel.SetContentSize(float32(width), float32(height))
-	l.currentText = msg
+	l.text = msg
 }
 }

+ 2 - 2
gui/menu.go

@@ -198,7 +198,7 @@ func (m *Menu) AddMenu(text string, subm *Menu) *MenuItem {
 	mi.submenu.autoOpen = true
 	mi.submenu.autoOpen = true
 	mi.menu = m
 	mi.menu = m
 	if !m.bar {
 	if !m.bar {
-		mi.ricon = NewLabel(string(icon.PlayArrow), true)
+		mi.ricon = NewIcon(string(icon.PlayArrow))
 		mi.Panel.Add(mi.ricon)
 		mi.Panel.Add(mi.ricon)
 	}
 	}
 	mi.Panel.Add(mi.submenu)
 	mi.Panel.Add(mi.submenu)
@@ -594,7 +594,7 @@ func (mi *MenuItem) SetIcon(icon string) *MenuItem {
 		mi.licon = nil
 		mi.licon = nil
 	}
 	}
 	// Sets the new icon
 	// Sets the new icon
-	mi.licon = NewLabel(icon, true)
+	mi.licon = NewIcon(icon)
 	mi.Panel.Add(mi.licon)
 	mi.Panel.Add(mi.licon)
 	mi.update()
 	mi.update()
 	return mi
 	return mi

+ 1 - 0
gui/style.go

@@ -12,6 +12,7 @@ import (
 type Style struct {
 type Style struct {
 	Font          *text.Font
 	Font          *text.Font
 	FontIcon      *text.Font
 	FontIcon      *text.Font
+	Label         LabelStyle
 	Button        ButtonStyles
 	Button        ButtonStyles
 	CheckRadio    CheckRadioStyles
 	CheckRadio    CheckRadioStyles
 	Edit          EditStyles
 	Edit          EditStyles

+ 12 - 11
gui/style_light.go

@@ -25,11 +25,6 @@ func NewLightStyle() *Style {
 	if err != nil {
 	if err != nil {
 		panic(err)
 		panic(err)
 	}
 	}
-	font.SetLineSpacing(1.0)
-	font.SetSize(14)
-	font.SetDPI(72)
-	font.SetFgColor4(math32.NewColor4("black"))
-	font.SetBgColor4(math32.NewColor4("black", 0))
 	s.Font = font
 	s.Font = font
 
 
 	// Creates icon font
 	// Creates icon font
@@ -38,11 +33,6 @@ func NewLightStyle() *Style {
 	if err != nil {
 	if err != nil {
 		panic(err)
 		panic(err)
 	}
 	}
-	fontIcon.SetLineSpacing(1.0)
-	fontIcon.SetSize(14)
-	fontIcon.SetDPI(72)
-	fontIcon.SetFgColor4(math32.NewColor4("black"))
-	fontIcon.SetBgColor4(math32.NewColor4("white", 0))
 	s.FontIcon = fontIcon
 	s.FontIcon = fontIcon
 
 
 	zeroBounds := RectBounds{0, 0, 0, 0}
 	zeroBounds := RectBounds{0, 0, 0, 0}
@@ -62,6 +52,16 @@ func NewLightStyle() *Style {
 	fgColorSel := math32.Color4{0, 0, 0, 1}
 	fgColorSel := math32.Color4{0, 0, 0, 1}
 	fgColorDis := math32.Color4{0.4, 0.4, 0.4, 1}
 	fgColorDis := math32.Color4{0.4, 0.4, 0.4, 1}
 
 
+	// Label style
+	s.Label = LabelStyle{}
+	s.Label.FontAttributes = text.FontAttributes{}
+	s.Label.FontAttributes.PointSize = 14
+	s.Label.FontAttributes.DPI = 72
+	s.Label.FontAttributes.Hinting = text.HintingNone
+	s.Label.FontAttributes.LineSpacing = 1.0
+	s.Label.BgColor = math32.Color4{0,0,0,0}
+	s.Label.FgColor = math32.Color4{0,0,0,1}
+
 	// Button styles
 	// Button styles
 	s.Button = ButtonStyles{}
 	s.Button = ButtonStyles{}
 	s.Button.Normal = ButtonStyle{}
 	s.Button.Normal = ButtonStyle{}
@@ -74,7 +74,8 @@ func NewLightStyle() *Style {
 	s.Button.Over.BgColor = bgColorOver
 	s.Button.Over.BgColor = bgColorOver
 	s.Button.Focus = s.Button.Over
 	s.Button.Focus = s.Button.Over
 	s.Button.Pressed = s.Button.Over
 	s.Button.Pressed = s.Button.Over
-	s.Button.Pressed.Border = twoBounds
+	s.Button.Pressed.Border = RectBounds{2, 2, 2, 2}
+	s.Button.Pressed.Padding = RectBounds{2, 2, 0, 4}
 	s.Button.Disabled = s.Button.Normal
 	s.Button.Disabled = s.Button.Normal
 	s.Button.Disabled.BorderColor = borderColorDis
 	s.Button.Disabled.BorderColor = borderColorDis
 	s.Button.Disabled.FgColor = fgColorDis
 	s.Button.Disabled.FgColor = fgColorDis

+ 3 - 3
gui/tabbar.go

@@ -78,7 +78,7 @@ func NewTabBar(width, height float32) *TabBar {
 	tb.Add(tb.list)
 	tb.Add(tb.list)
 
 
 	// Creates list icon button
 	// Creates list icon button
-	tb.listButton = NewLabel(tb.styles.ListButtonIcon, true)
+	tb.listButton = NewIcon(tb.styles.ListButtonIcon)
 	tb.listButton.SetPaddingsFrom(&tb.styles.ListButtonPaddings)
 	tb.listButton.SetPaddingsFrom(&tb.styles.ListButtonPaddings)
 	tb.listButton.Subscribe(OnMouseDown, tb.onListButton)
 	tb.listButton.Subscribe(OnMouseDown, tb.onListButton)
 	tb.Add(tb.listButton)
 	tb.Add(tb.listButton)
@@ -409,7 +409,7 @@ func newTab(text string, tb *TabBar, styles *TabStyles) *Tab {
 	// Setup the header panel
 	// Setup the header panel
 	tab.header.Initialize(0, 0)
 	tab.header.Initialize(0, 0)
 	tab.label = NewLabel(text)
 	tab.label = NewLabel(text)
-	tab.iconClose = NewLabel(styles.IconClose, true)
+	tab.iconClose = NewIcon(styles.IconClose)
 	tab.header.Add(tab.label)
 	tab.header.Add(tab.label)
 	tab.header.Add(tab.iconClose)
 	tab.header.Add(tab.iconClose)
 	// Creates the bottom panel
 	// Creates the bottom panel
@@ -493,7 +493,7 @@ func (tab *Tab) SetIcon(icon string) *Tab {
 	}
 	}
 	// Creates or updates icon
 	// Creates or updates icon
 	if tab.icon == nil {
 	if tab.icon == nil {
-		tab.icon = NewLabel(icon, true)
+		tab.icon = NewIcon(icon)
 		tab.icon.SetPaddingsFrom(&tab.styles.IconPaddings)
 		tab.icon.SetPaddingsFrom(&tab.styles.IconPaddings)
 		tab.header.Add(tab.icon)
 		tab.header.Add(tab.icon)
 	} else {
 	} else {

+ 1 - 1
gui/table.go

@@ -235,7 +235,7 @@ func NewTable(width, height float32, cols []TableColumn) (*Table, error) {
 		c.resize = cdesc.Resize
 		c.resize = cdesc.Resize
 		// Adds optional sort icon
 		// Adds optional sort icon
 		if c.sort != TableSortNone {
 		if c.sort != TableSortNone {
-			c.ricon = NewLabel(string(tableSortedNoneIcon), true)
+			c.ricon = NewIcon(string(tableSortedNoneIcon))
 			c.Add(c.ricon)
 			c.Add(c.ricon)
 			c.ricon.Subscribe(OnMouseDown, func(evname string, ev interface{}) {
 			c.ricon.Subscribe(OnMouseDown, func(evname string, ev interface{}) {
 				t.onRicon(evname, c)
 				t.onRicon(evname, c)

+ 1 - 1
gui/tree.go

@@ -212,7 +212,7 @@ func newTreeNode(text string, tree *Tree, parNode *TreeNode) *TreeNode {
 
 
 	// Create node icon
 	// Create node icon
 	n.icon.initialize("", StyleDefault().FontIcon)
 	n.icon.initialize("", StyleDefault().FontIcon)
-	n.icon.SetFontSize(n.label.FontSize() * 1.3)
+	n.icon.SetFontSize(StyleDefault().Label.PointSize * 1.3)
 	n.Panel.Add(&n.icon)
 	n.Panel.Add(&n.icon)
 
 
 	// Subscribe to events
 	// Subscribe to events

+ 22 - 3
renderer/shaders/panel_fragment.glsl

@@ -72,18 +72,37 @@ void main() {
 
 
     // Check if fragment is inside content area
     // Check if fragment is inside content area
     if (checkRect(Content)) {
     if (checkRect(Content)) {
+
         // If no texture, the color will be the material color.
         // If no texture, the color will be the material color.
         vec4 color = ContentColor;
         vec4 color = ContentColor;
+
 		if (TextureValid) {
 		if (TextureValid) {
             // Adjust texture coordinates to fit texture inside the content area
             // Adjust texture coordinates to fit texture inside the content area
             vec2 offset = vec2(-Content[0], -Content[1]);
             vec2 offset = vec2(-Content[0], -Content[1]);
             vec2 factor = vec2(1/Content[2], 1/Content[3]);
             vec2 factor = vec2(1/Content[2], 1/Content[3]);
             vec2 texcoord = (FragTexcoord + offset) * factor;
             vec2 texcoord = (FragTexcoord + offset) * factor;
             vec4 texColor = texture(MatTexture, texcoord * MatTexRepeat + MatTexOffset);
             vec4 texColor = texture(MatTexture, texcoord * MatTexRepeat + MatTexOffset);
-            // Mix content color with texture color ???
-            //color = mix(color, texColor, texColor.a);
-            color = texColor;
+
+            // Mix content color with texture color.
+            // Note that doing a simple linear interpolation (e.g. using mix()) is not correct!
+            // The right formula can be found here: https://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending
+            // For a more in-depth discussion: http://apoorvaj.io/alpha-compositing-opengl-blending-and-premultiplied-alpha.html#toc4
+
+            // Pre-multiply the content color
+            vec4 contentPre = ContentColor;
+            contentPre.rgb *= contentPre.a;
+
+            // Pre-multiply the texture color
+            vec4 texPre = texColor;
+            texPre.rgb *= texPre.a;
+
+            // Combine colors the premultiplied final color
+            color = texPre + contentPre * (1 - texPre.a);
+
+            // Un-pre-multiply (pre-divide? :P)
+            color.rgb /= color.a;
 		}
 		}
+
         FragColor = color;
         FragColor = color;
         return;
         return;
     }
     }

+ 22 - 3
renderer/shaders/sources.go

@@ -331,18 +331,37 @@ void main() {
 
 
     // Check if fragment is inside content area
     // Check if fragment is inside content area
     if (checkRect(Content)) {
     if (checkRect(Content)) {
+
         // If no texture, the color will be the material color.
         // If no texture, the color will be the material color.
         vec4 color = ContentColor;
         vec4 color = ContentColor;
+
 		if (TextureValid) {
 		if (TextureValid) {
             // Adjust texture coordinates to fit texture inside the content area
             // Adjust texture coordinates to fit texture inside the content area
             vec2 offset = vec2(-Content[0], -Content[1]);
             vec2 offset = vec2(-Content[0], -Content[1]);
             vec2 factor = vec2(1/Content[2], 1/Content[3]);
             vec2 factor = vec2(1/Content[2], 1/Content[3]);
             vec2 texcoord = (FragTexcoord + offset) * factor;
             vec2 texcoord = (FragTexcoord + offset) * factor;
             vec4 texColor = texture(MatTexture, texcoord * MatTexRepeat + MatTexOffset);
             vec4 texColor = texture(MatTexture, texcoord * MatTexRepeat + MatTexOffset);
-            // Mix content color with texture color ???
-            //color = mix(color, texColor, texColor.a);
-            color = texColor;
+
+            // Mix content color with texture color.
+            // Note that doing a simple linear interpolation (e.g. using mix()) is not correct!
+            // The right formula can be found here: https://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending
+            // For a more in-depth discussion: http://apoorvaj.io/alpha-compositing-opengl-blending-and-premultiplied-alpha.html#toc4
+
+            // Pre-multiply the content color
+            vec4 contentPre = ContentColor;
+            contentPre.rgb *= contentPre.a;
+
+            // Pre-multiply the texture color
+            vec4 texPre = texColor;
+            texPre.rgb *= texPre.a;
+
+            // Combine colors the premultiplied final color
+            color = texPre + contentPre * (1 - texPre.a);
+
+            // Un-pre-multiply (pre-divide? :P)
+            color.rgb /= color.a;
 		}
 		}
+
         FragColor = color;
         FragColor = color;
         return;
         return;
     }
     }

+ 120 - 131
text/font.go

@@ -17,21 +17,25 @@ import (
 )
 )
 
 
 // Font represents a TrueType font face.
 // Font represents a TrueType font face.
+// Attributes must be set prior to drawing.
 type Font struct {
 type Font struct {
-	ttf         *truetype.Font
-	face        font.Face
-	fgColor     math32.Color4
-	bgColor     math32.Color4
-	fontSize    float64
-	fontDPI     float64
-	lineSpacing float64 // [0,1] relative to font height
-	fg          *image.Uniform
-	bg          *image.Uniform
-	hinting     font.Hinting
-	changed     bool
+	ttf     *truetype.Font // The TrueType font
+	face    font.Face      // The font face
+	attrib  FontAttributes // Internal attribute cache
+	fg      *image.Uniform // Text color cache
+	bg      *image.Uniform // Background color cache
+	changed bool           // Whether attributes have changed and the font face needs to be recreated
 }
 }
 
 
-// Font hinting types.
+// FontAttributes contains tunable attributes of a font.
+type FontAttributes struct {
+	PointSize   float64      // Point size of the font
+	DPI         float64      // Resolution of the font in dots per inch
+	LineSpacing float64      // Spacing between lines (in terms of font height)
+	Hinting     font.Hinting // Font hinting
+}
+
+// Font Hinting types.
 const (
 const (
 	HintingNone     = font.HintingNone
 	HintingNone     = font.HintingNone
 	HintingVertical = font.HintingVertical
 	HintingVertical = font.HintingVertical
@@ -39,17 +43,17 @@ const (
 )
 )
 
 
 // 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) {
+func NewFont(ttfFile string) (*Font, error) {
 
 
 	// Reads font bytes
 	// Reads font bytes
-	fontBytes, err := ioutil.ReadFile(fontfile)
+	fontBytes, err := ioutil.ReadFile(ttfFile)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 	return NewFontFromData(fontBytes)
 	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 TTF data.
 func NewFontFromData(fontData []byte) (*Font, error) {
 func NewFontFromData(fontData []byte) (*Font, error) {
 
 
 	// Parses the font data
 	// Parses the font data
@@ -60,123 +64,93 @@ func NewFontFromData(fontData []byte) (*Font, error) {
 
 
 	f := new(Font)
 	f := new(Font)
 	f.ttf = ttf
 	f.ttf = ttf
-	f.fontSize = 12
-	f.fontDPI = 72
-	f.lineSpacing = 1.0
-	f.hinting = font.HintingNone
-	f.SetFgColor4(&math32.Color4{0, 0, 0, 1})
-	f.SetBgColor4(&math32.Color4{1, 1, 1, 0})
-	f.changed = false
-
-	// Creates font face
+
+	// Initialize with default values
+	f.attrib = FontAttributes{}
+	f.attrib.PointSize = 12
+	f.attrib.DPI = 72
+	f.attrib.LineSpacing = 1.0
+	f.attrib.Hinting = font.HintingNone
+	f.SetColor(&math32.Color4{0, 0, 0, 1})
+
+	// Create font face
 	f.face = truetype.NewFace(f.ttf, &truetype.Options{
 	f.face = truetype.NewFace(f.ttf, &truetype.Options{
-		Size:    f.fontSize,
-		DPI:     f.fontDPI,
-		Hinting: f.hinting,
+		Size:    f.attrib.PointSize,
+		DPI:     f.attrib.DPI,
+		Hinting: f.attrib.Hinting,
 	})
 	})
+
 	return f, nil
 	return f, nil
 }
 }
 
 
-// SetSize sets the size of the font.
-func (f *Font) SetSize(size float64) {
+// SetPointSize sets the point size of the font.
+func (f *Font) SetPointSize(size float64) {
 
 
-	if size == f.fontSize {
+	if size == f.attrib.PointSize {
 		return
 		return
 	}
 	}
-	f.fontSize = size
+	f.attrib.PointSize = size
 	f.changed = true
 	f.changed = true
 }
 }
 
 
-// Size returns the current font size.
-func (f *Font) Size() float64 {
-
-	return f.fontSize
-}
-
-// SetDPI sets the current DPI of the font.
+// SetDPI sets the resolution of the font in dots per inches (DPI).
 func (f *Font) SetDPI(dpi float64) {
 func (f *Font) SetDPI(dpi float64) {
 
 
-	if dpi == f.fontDPI {
+	if dpi == f.attrib.DPI {
 		return
 		return
 	}
 	}
-	f.fontDPI = dpi
+	f.attrib.DPI = dpi
 	f.changed = true
 	f.changed = true
 }
 }
 
 
-// DPI returns the current font DPI.
-func (f *Font) DPI() float64 {
-
-	return f.fontDPI
-}
-
-// SetLineSpacing sets the spacing between lines.
+// SetLineSpacing sets the amount of spacing between lines (in terms of font height).
 func (f *Font) SetLineSpacing(spacing float64) {
 func (f *Font) SetLineSpacing(spacing float64) {
 
 
-	f.lineSpacing = spacing
-}
-
-// LineSpacing returns the current spacing between lines.
-func (f *Font) LineSpacing() float64 {
-
-	return f.lineSpacing
+	if spacing == f.attrib.LineSpacing {
+		return
+	}
+	f.attrib.LineSpacing = spacing
+	f.changed = true
 }
 }
 
 
 // SetHinting sets the hinting type.
 // SetHinting sets the hinting type.
 func (f *Font) SetHinting(hinting font.Hinting) {
 func (f *Font) SetHinting(hinting font.Hinting) {
 
 
-	if hinting == f.hinting {
+	if hinting == f.attrib.Hinting {
 		return
 		return
 	}
 	}
-	f.hinting = hinting
+	f.attrib.Hinting = hinting
 	f.changed = true
 	f.changed = true
 }
 }
 
 
-// Hinting returns the current hinting type.
-func (f *Font) Hinting() font.Hinting {
+// SetFgColor sets the text color.
+func (f *Font) SetFgColor(color *math32.Color4) {
 
 
-	return f.hinting
-}
-
-// 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.FromColor(color, 1.0)
-	f.fg = image.NewUniform(Color4RGBA(&f.fgColor))
-}
-
-// 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))
 	f.fg = image.NewUniform(Color4RGBA(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).
-func (f *Font) SetBgColor(color *math32.Color) {
+// SetBgColor sets the background color.
+func (f *Font) SetBgColor(color *math32.Color4) {
 
 
-	f.bgColor.FromColor(color, 1.0)
-	f.bg = image.NewUniform(Color4RGBA(&f.fgColor))
+	f.bg = image.NewUniform(Color4RGBA(color))
 }
 }
 
 
-// SetBgColor4 sets the current background color of the font.
-func (f *Font) SetBgColor4(color *math32.Color4) {
+// SetColor sets the text color to the specified value and makes the background color transparent.
+// Note that for perfect transparency in the anti-aliased region it's important that the RGB components
+// of the text and background colors match. This method handles that for the user.
+func (f *Font) SetColor(fg *math32.Color4) {
 
 
-	f.bgColor = *color
-	f.bg = image.NewUniform(Color4RGBA(color))
+	f.fg = image.NewUniform(Color4RGBA(fg))
+	f.bg = image.NewUniform(Color4RGBA(&math32.Color4{fg.R, fg.G, fg.B, 0}))
 }
 }
 
 
-// BgColor4 returns the current background color.
-func (f *Font) BgColor4() math32.Color4 {
+// SetAttributes sets the font attributes.
+func (f *Font) SetAttributes(fa *FontAttributes) {
 
 
-	return f.bgColor
+	f.SetPointSize(fa.PointSize)
+	f.SetDPI(fa.DPI)
+	f.SetLineSpacing(fa.LineSpacing)
+	f.SetHinting(fa.Hinting)
 }
 }
 
 
 // updateFace updates the font face if parameters have changed.
 // updateFace updates the font face if parameters have changed.
@@ -184,17 +158,16 @@ func (f *Font) updateFace() {
 
 
 	if f.changed {
 	if f.changed {
 		f.face = truetype.NewFace(f.ttf, &truetype.Options{
 		f.face = truetype.NewFace(f.ttf, &truetype.Options{
-			Size:    f.fontSize,
-			DPI:     f.fontDPI,
-			Hinting: f.hinting,
+			Size:    f.attrib.PointSize,
+			DPI:     f.attrib.DPI,
+			Hinting: f.attrib.Hinting,
 		})
 		})
 		f.changed = false
 		f.changed = false
 	}
 	}
 }
 }
 
 
-// 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).
+// 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) {
 func (f *Font) MeasureText(text string) (int, int) {
 
 
 	// Create font drawer
 	// Create font drawer
@@ -205,7 +178,7 @@ func (f *Font) MeasureText(text string) (int, int) {
 	var width, height int
 	var width, height int
 	metrics := f.face.Metrics()
 	metrics := f.face.Metrics()
 	lineHeight := (metrics.Ascent + metrics.Descent).Ceil()
 	lineHeight := (metrics.Ascent + metrics.Descent).Ceil()
-	lineGap := int((f.lineSpacing - float64(1)) * float64(lineHeight))
+	lineGap := int((f.attrib.LineSpacing - float64(1)) * float64(lineHeight))
 
 
 	lines := strings.Split(text, "\n")
 	lines := strings.Split(text, "\n")
 	for i, s := range lines {
 	for i, s := range lines {
@@ -222,14 +195,47 @@ func (f *Font) MeasureText(text string) (int, int) {
 	return width, height
 	return width, height
 }
 }
 
 
-// Metrics returns the font metrics
+// Metrics returns the font metrics.
 func (f *Font) Metrics() font.Metrics {
 func (f *Font) Metrics() font.Metrics {
 
 
 	f.updateFace()
 	f.updateFace()
 	return f.face.Metrics()
 	return f.face.Metrics()
 }
 }
 
 
-// Canvas is an image to draw text
+// DrawText draws the specified text on a new, tightly fitting image, and returns a pointer to the image.
+func (f *Font) DrawText(text string) *image.RGBA {
+
+	width, height := f.MeasureText(text)
+	img := image.NewRGBA(image.Rect(0, 0, width, height))
+	draw.Draw(img, img.Bounds(), f.bg, image.ZP, draw.Src)
+	f.DrawTextOnImage(text, 0, 0, img)
+
+	return img
+}
+
+// DrawTextOnImage draws the specified text on the specified image at the specified coordinates.
+func (f *Font) DrawTextOnImage(text string, x, y int, dst *image.RGBA) {
+
+	f.updateFace()
+	d := &font.Drawer{Dst: dst, Src: f.fg, Face: f.face}
+
+	// Draw text
+	metrics := f.face.Metrics()
+	py := y + metrics.Ascent.Round()
+	lineHeight := (metrics.Ascent + metrics.Descent).Ceil()
+	lineGap := int((f.attrib.LineSpacing - float64(1)) * float64(lineHeight))
+	lines := strings.Split(text, "\n")
+	for i, s := range lines {
+		d.Dot = fixed.P(x, py)
+		d.DrawString(s)
+		py += lineHeight
+		if i > 1 {
+			py += lineGap
+		}
+	}
+}
+
+// Canvas is an image to draw on.
 type Canvas struct {
 type Canvas struct {
 	RGBA    *image.RGBA
 	RGBA    *image.RGBA
 	bgColor *image.Uniform
 	bgColor *image.Uniform
@@ -255,30 +261,14 @@ func NewCanvas(width, height int, bgColor *math32.Color4) *Canvas {
 // The supplied text string can contain line break escape sequences (\n).
 // The supplied text string can contain line break escape sequences (\n).
 func (c Canvas) DrawText(x, y int, text string, f *Font) {
 func (c Canvas) DrawText(x, y int, text string, f *Font) {
 
 
-	// Creates drawer
-	f.updateFace()
-	d := &font.Drawer{Dst: c.RGBA, Src: f.fg, Face: f.face}
-
-	// 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 i, s := range lines {
-		d.Dot = fixed.P(x, py)
-		d.DrawString(s)
-		py += lineHeight
-		if i > 1 {
-			py += lineGap
-		}
-	}
+	f.DrawTextOnImage(text, x, y, c.RGBA)
 }
 }
 
 
 // DrawTextCaret draws text at the specified position (in pixels)
 // DrawTextCaret draws text at the specified position (in pixels)
 // of this canvas, using the specified font, and also a caret at
 // of this canvas, using the specified font, and also a caret at
 // the specified line and column.
 // the specified line and column.
 // The supplied text string can contain line break escape sequences (\n).
 // The supplied text string can contain line break escape sequences (\n).
+// TODO Implement caret as a gui.Panel in gui.Edit
 func (c Canvas) DrawTextCaret(x, y int, text string, f *Font, line, col int) error {
 func (c Canvas) DrawTextCaret(x, y int, text string, f *Font, line, col int) error {
 
 
 	// Creates drawer
 	// Creates drawer
@@ -289,7 +279,7 @@ func (c Canvas) DrawTextCaret(x, y int, text string, f *Font, line, col int) err
 	metrics := f.face.Metrics()
 	metrics := f.face.Metrics()
 	py := y + metrics.Ascent.Round()
 	py := y + metrics.Ascent.Round()
 	lineHeight := (metrics.Ascent + metrics.Descent).Ceil()
 	lineHeight := (metrics.Ascent + metrics.Descent).Ceil()
-	lineGap := int((f.lineSpacing - float64(1)) * float64(lineHeight))
+	lineGap := int((f.attrib.LineSpacing - float64(1)) * float64(lineHeight))
 	lines := strings.Split(text, "\n")
 	lines := strings.Split(text, "\n")
 	for l, s := range lines {
 	for l, s := range lines {
 		d.Dot = fixed.P(x, py)
 		d.Dot = fixed.P(x, py)
@@ -298,11 +288,9 @@ func (c Canvas) DrawTextCaret(x, y int, text string, f *Font, line, col int) err
 		if l == line && col <= StrCount(s) {
 		if l == line && col <= StrCount(s) {
 			width, _ := f.MeasureText(StrPrefix(s, col))
 			width, _ := f.MeasureText(StrPrefix(s, col))
 			// Draw caret vertical line
 			// Draw caret vertical line
-			caretH := int(f.fontSize) + 2
-			//caretY := int(pt.Y>>6) - int(f.fontSize) + 2
-			caretY := int(d.Dot.Y>>6) - int(f.fontSize) + 2
-			fgCol := f.FgColor4()
-			color := Color4RGBA(&fgCol)
+			caretH := int(f.attrib.PointSize) + 2
+			caretY := int(d.Dot.Y>>6) - int(f.attrib.PointSize) + 2
+			color := Color4RGBA(&math32.Color4{0,0,0,1}) // Hardcoded to black
 			for j := caretY; j < caretY+caretH; j++ {
 			for j := caretY; j < caretY+caretH; j++ {
 				c.RGBA.Set(x+width, j, color)
 				c.RGBA.Set(x+width, j, color)
 			}
 			}
@@ -313,7 +301,8 @@ func (c Canvas) DrawTextCaret(x, y int, text string, f *Font, line, col int) err
 		}
 		}
 	}
 	}
 
 
-	//	pt := freetype.Pt(font.marginX+x, font.marginY+y+int(font.ctx.PointToFixed(font.fontSize)>>6))
+	// TODO remove ?
+	//	pt := freetype.Pt(font.marginX+x, font.marginY+y+int(font.ctx.PointToFixed(font.attrib.PointSize)>>6))
 	//	for l, s := range lines {
 	//	for l, s := range lines {
 	//		// Draw string
 	//		// Draw string
 	//		_, err := font.ctx.DrawString(s, pt)
 	//		_, err := font.ctx.DrawString(s, pt)
@@ -327,25 +316,25 @@ func (c Canvas) DrawTextCaret(x, y int, text string, f *Font, line, col int) err
 	//				return err
 	//				return err
 	//			}
 	//			}
 	//			// Draw caret vertical line
 	//			// Draw caret vertical line
-	//			caretH := int(font.fontSize) + 2
-	//			caretY := int(pt.Y>>6) - int(font.fontSize) + 2
+	//			caretH := int(font.PointSize) + 2
+	//			caretY := int(pt.Y>>6) - int(font.PointSize) + 2
 	//			color := Color4RGBA(&math32.Color4{0, 0, 0, 1})
 	//			color := Color4RGBA(&math32.Color4{0, 0, 0, 1})
 	//			for j := caretY; j < caretY+caretH; j++ {
 	//			for j := caretY; j < caretY+caretH; j++ {
 	//				c.RGBA.Set(x+width, j, color)
 	//				c.RGBA.Set(x+width, j, color)
 	//			}
 	//			}
 	//		}
 	//		}
 	//		// Increment y coordinate
 	//		// Increment y coordinate
-	//		pt.Y += font.ctx.PointToFixed(font.fontSize * font.lineSpacing)
+	//		pt.Y += font.ctx.PointToFixed(font.PointSize * font.LineSpacing)
 	//	}
 	//	}
 	return nil
 	return nil
 }
 }
 
 
-// Color4RGBA converts a math32.Color4 to Go's color.RGBA
+// Color4RGBA converts a math32.Color4 to Go's color.RGBA.
 func Color4RGBA(c *math32.Color4) color.RGBA {
 func Color4RGBA(c *math32.Color4) color.RGBA {
 
 
 	red := uint8(c.R * 0xFF)
 	red := uint8(c.R * 0xFF)
 	green := uint8(c.G * 0xFF)
 	green := uint8(c.G * 0xFF)
 	blue := uint8(c.B * 0xFF)
 	blue := uint8(c.B * 0xFF)
-	al := uint8(c.A * 0xFF)
-	return color.RGBA{red, green, blue, al}
+	alpha := uint8(c.A * 0xFF)
+	return color.RGBA{red, green, blue, alpha}
 }
 }