Added Fonts() to context similarly as Textures().
- Fonts are now managed by context instead of the implementation specific renderers.
This commit is contained in:
parent
02ee819a99
commit
3591e22c97
@ -22,8 +22,9 @@ func newFont(f *allg5.Font) *font {
|
||||
return &font{f}
|
||||
}
|
||||
|
||||
func (f *font) Destroy() {
|
||||
func (f *font) Destroy() error {
|
||||
f.Font.Destroy()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *font) Height() float32 {
|
||||
|
@ -47,7 +47,7 @@ func NewRenderer(w, h int, opts allg5.NewDisplayOptions) (*Renderer, error) {
|
||||
})
|
||||
clean = nil
|
||||
|
||||
return &Renderer{disp, eq, nil, map[string]*font{}, user, &ui.OSResources{}, ui.KeyState{}, ui.KeyModifierNone, ui.MouseCursorDefault}, nil
|
||||
return &Renderer{disp, eq, nil, user, &ui.OSResources{}, ui.KeyState{}, ui.KeyModifierNone, ui.MouseCursorDefault}, nil
|
||||
}
|
||||
|
||||
// Renderer implements ui.Renderer using Allegro 5.
|
||||
@ -55,7 +55,6 @@ type Renderer struct {
|
||||
disp *allg5.Display
|
||||
eq *allg5.EventQueue
|
||||
unh func(allg5.Event)
|
||||
ft map[string]*font
|
||||
user *allg5.UserEventSource
|
||||
res ui.Resources
|
||||
|
||||
@ -149,10 +148,6 @@ func (r *Renderer) Refresh() {
|
||||
func (r *Renderer) Destroy() error {
|
||||
r.user.Destroy()
|
||||
r.eq.Destroy()
|
||||
for _, f := range r.ft {
|
||||
f.Destroy()
|
||||
}
|
||||
r.ft = nil
|
||||
r.disp.Destroy()
|
||||
r.res.Destroy()
|
||||
return nil
|
||||
@ -164,6 +159,18 @@ func (r *Renderer) Clear(c color.Color) {
|
||||
allg5.ClearToColor(newColor(c))
|
||||
}
|
||||
|
||||
func (r *Renderer) CreateFontPath(path string, size int) (ui.Font, error) {
|
||||
path, err := r.res.FetchResource(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f, err := allg5.LoadTTFFont(path, size)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &font{f}, nil
|
||||
}
|
||||
|
||||
func (r *Renderer) createTexture(source ui.ImageSource, keepSource bool) (ui.Texture, error) {
|
||||
im, err := source.CreateImage()
|
||||
if err != nil {
|
||||
@ -237,10 +244,6 @@ func (r *Renderer) FillRectangle(rect geom.RectangleF32, c color.Color) {
|
||||
allg5.DrawFilledRectangle(rect.Min.X, rect.Min.Y, rect.Max.X, rect.Max.Y, newColor(c))
|
||||
}
|
||||
|
||||
func (r *Renderer) Font(name string) ui.Font {
|
||||
return r.ft[name]
|
||||
}
|
||||
|
||||
func (r *Renderer) mustGetBitmap(t ui.Texture) *allg5.Bitmap {
|
||||
texture, ok := t.(*texture)
|
||||
if !ok {
|
||||
@ -255,33 +258,6 @@ func (r *Renderer) Rectangle(rect geom.RectangleF32, c color.Color, thickness fl
|
||||
allg5.DrawRectangle(minX, minY, maxX, maxY, newColor(c), thickness)
|
||||
}
|
||||
|
||||
func (r *Renderer) RegisterFont(name, path string, size int) error {
|
||||
path, err := r.res.FetchResource(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
font, err := allg5.LoadTTFFont(path, size)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var prev = r.ft[name]
|
||||
if prev != nil {
|
||||
prev.Destroy()
|
||||
}
|
||||
r.ft[name] = newFont(font)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Renderer) RegisterFonts(path string, fonts ...FontDefinition) error {
|
||||
for _, f := range fonts {
|
||||
err := r.RegisterFont(path, f.Name, f.Size)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Renderer) RenderTo(texture ui.Texture) {
|
||||
bmp := r.mustGetBitmap(texture)
|
||||
bmp.SetAsTarget()
|
||||
@ -325,20 +301,20 @@ func (r *Renderer) Target() ui.Texture {
|
||||
return &texture{allg5.CurrentTarget(), nil}
|
||||
}
|
||||
|
||||
func (r *Renderer) text(p geom.PointF32, font string, c color.Color, t string, align allg5.HorizontalAlignment) {
|
||||
var f = r.ft[font]
|
||||
if f == nil {
|
||||
func (r *Renderer) text(f ui.Font, p geom.PointF32, c color.Color, t string, align allg5.HorizontalAlignment) {
|
||||
font, ok := f.(*font)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
x, y := snap(p)
|
||||
f.Draw(x, y, newColor(c), align, t)
|
||||
font.Draw(x, y, newColor(c), align, t)
|
||||
}
|
||||
|
||||
func (r *Renderer) Text(p geom.PointF32, font string, c color.Color, t string) {
|
||||
r.text(p, font, c, t, allg5.AlignLeft)
|
||||
func (r *Renderer) Text(font ui.Font, p geom.PointF32, c color.Color, t string) {
|
||||
r.text(font, p, c, t, allg5.AlignLeft)
|
||||
}
|
||||
|
||||
func (r *Renderer) TextAlign(p geom.PointF32, font string, c color.Color, t string, align ui.HorizontalAlignment) {
|
||||
func (r *Renderer) TextAlign(font ui.Font, p geom.PointF32, c color.Color, t string, align ui.HorizontalAlignment) {
|
||||
var alignment = allg5.AlignLeft
|
||||
switch align {
|
||||
case ui.AlignCenter:
|
||||
@ -346,7 +322,7 @@ func (r *Renderer) TextAlign(p geom.PointF32, font string, c color.Color, t stri
|
||||
case ui.AlignRight:
|
||||
alignment = allg5.AlignRight
|
||||
}
|
||||
r.text(p, font, c, t, alignment)
|
||||
r.text(font, p, c, t, alignment)
|
||||
}
|
||||
|
||||
// Utility functions
|
||||
|
10
colors.go
10
colors.go
@ -22,7 +22,7 @@ func HexColor(s string) (color.RGBA, error) {
|
||||
if len(match[4]) > 0 {
|
||||
a = values[3]
|
||||
}
|
||||
return color.RGBA{R: uint8(values[0]), G: uint8(values[1]), B: uint8(values[2]), A: uint8(a)}, nil
|
||||
return RGBA(uint8(values[0]), uint8(values[1]), uint8(values[2]), uint8(a)), nil
|
||||
}
|
||||
|
||||
// HexToInt tries to convert a string with hexadecimal characters to an integer.
|
||||
@ -64,3 +64,11 @@ func MustHexColor(s string) color.RGBA {
|
||||
}
|
||||
return color
|
||||
}
|
||||
|
||||
// RGB creates an opaque color with the specified red, green and red values.
|
||||
func RGB(r, g, b byte) color.RGBA { return RGBA(r, g, b, 0xff) }
|
||||
|
||||
// RGB creates a color with the specified red, green, red and alpha values.
|
||||
func RGBA(r, g, b, a byte) color.RGBA {
|
||||
return color.RGBA{R: r, G: g, B: b, A: a}
|
||||
}
|
||||
|
@ -9,6 +9,11 @@ type Font struct {
|
||||
*ttf.Font
|
||||
}
|
||||
|
||||
func (f *Font) Destroy() error {
|
||||
f.Font.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Font) Height() float32 {
|
||||
return float32(f.Font.Height())
|
||||
}
|
||||
|
@ -22,7 +22,6 @@ type Renderer struct {
|
||||
window *sdl.Window
|
||||
renderer *sdl.Renderer
|
||||
refresh uint32
|
||||
fonts map[string]*Font
|
||||
resources ui.Resources
|
||||
|
||||
mouse geom.PointF32
|
||||
@ -88,7 +87,6 @@ func NewRenderer(title string, width, height int32, opts NewRendererOptions) (*R
|
||||
window: window,
|
||||
renderer: renderer,
|
||||
refresh: refresh,
|
||||
fonts: map[string]*Font{},
|
||||
resources: &ui.OSResources{},
|
||||
cursors: map[sdl.SystemCursor]*sdl.Cursor{},
|
||||
}, nil
|
||||
@ -205,9 +203,6 @@ func (r *Renderer) Refresh() {
|
||||
// Lifetime
|
||||
|
||||
func (r *Renderer) Destroy() error {
|
||||
for _, f := range r.fonts {
|
||||
f.Close()
|
||||
}
|
||||
r.renderer.Destroy()
|
||||
r.window.Destroy()
|
||||
ttf.Quit()
|
||||
@ -226,6 +221,18 @@ func (r *Renderer) Clear(c color.Color) {
|
||||
r.renderer.Clear()
|
||||
}
|
||||
|
||||
func (r *Renderer) CreateFontPath(path string, size int) (ui.Font, error) {
|
||||
path, err := r.resources.FetchResource(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
font, err := ttf.OpenFont(path, size)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Font{font}, nil
|
||||
}
|
||||
|
||||
func (r *Renderer) createTexture(source ui.ImageSource, keepSource bool) (ui.Texture, error) {
|
||||
m, err := source.CreateImage()
|
||||
if err != nil {
|
||||
@ -307,10 +314,6 @@ func (r *Renderer) FillRectangle(rect geom.RectangleF32, c color.Color) {
|
||||
r.renderer.FillRect(SDLRectanglePtr(rect))
|
||||
}
|
||||
|
||||
func (r *Renderer) Font(name string) ui.Font {
|
||||
return r.fonts[name]
|
||||
}
|
||||
|
||||
func (r *Renderer) Rectangle(rect geom.RectangleF32, c color.Color, thickness float32) {
|
||||
r.SetDrawColorGo(c)
|
||||
if rect.Dx() == 0 { // SDL doesn't draw a 1 px wide line when Dx() == 0 && thickness == 1
|
||||
@ -333,19 +336,6 @@ func (r *Renderer) Rectangle(rect geom.RectangleF32, c color.Color, thickness fl
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Renderer) RegisterFont(name, path string, size int) error {
|
||||
path, err := r.resources.FetchResource(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
font, err := ttf.OpenFont(path, size)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.fonts[name] = &Font{font}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Renderer) RenderTo(t ui.Texture) {
|
||||
texture, ok := t.(sdlTexture)
|
||||
if ok {
|
||||
@ -397,8 +387,8 @@ func (r *Renderer) Target() ui.Texture {
|
||||
return &Texture{target}
|
||||
}
|
||||
|
||||
func (r *Renderer) Text(p geom.PointF32, font string, color color.Color, text string) {
|
||||
f := r.Font(font).(*Font)
|
||||
func (r *Renderer) Text(font ui.Font, p geom.PointF32, color color.Color, text string) {
|
||||
f := font.(*Font)
|
||||
|
||||
surface, err := f.RenderUTF8Blended(text, ColorSDL(color))
|
||||
if err != nil {
|
||||
@ -414,16 +404,16 @@ func (r *Renderer) Text(p geom.PointF32, font string, color color.Color, text st
|
||||
r.DrawTexture(&Texture{texture}, p)
|
||||
}
|
||||
|
||||
func (r *Renderer) TextAlign(p geom.PointF32, font string, color color.Color, text string, align ui.HorizontalAlignment) {
|
||||
func (r *Renderer) TextAlign(font ui.Font, p geom.PointF32, color color.Color, text string, align ui.HorizontalAlignment) {
|
||||
switch align {
|
||||
case ui.AlignLeft:
|
||||
r.Text(p, font, color, text)
|
||||
r.Text(font, p, color, text)
|
||||
case ui.AlignCenter:
|
||||
width := r.Font(font).(*Font).WidthOf(text)
|
||||
r.Text(p.Add2D(-.5*width, 0), font, color, text)
|
||||
width := font.WidthOf(text)
|
||||
r.Text(font, p.Add2D(-.5*width, 0), color, text)
|
||||
case ui.AlignRight:
|
||||
width := r.Font(font).(*Font).WidthOf(text)
|
||||
r.Text(p.Add2D(-width, 0), font, color, text)
|
||||
width := font.WidthOf(text)
|
||||
r.Text(font, p.Add2D(-width, 0), color, text)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ func BuildIconButton(icon, text string, fn func(b *Button)) *Button {
|
||||
|
||||
func (b *Button) desiredSize(ctx Context) geom.PointF32 {
|
||||
var pad = ctx.Style().Dimensions.TextPadding
|
||||
var font = ctx.Renderer().Font(b.FontName(ctx))
|
||||
var font = ctx.Fonts().Font(b.FontName(ctx))
|
||||
var w, h float32 = 0, font.Height()
|
||||
if len(b.Text) != 0 {
|
||||
w += pad + font.WidthOf(b.Text)
|
||||
@ -144,9 +144,9 @@ func (b *Button) Render(ctx Context) {
|
||||
pos.X += iconWidth + pad
|
||||
}
|
||||
if len(b.Text) != 0 {
|
||||
var fontName = b.FontName(ctx)
|
||||
var font = ctx.Renderer().Font(fontName)
|
||||
ctx.Renderer().Text(geom.PtF32(pos.X, pos.Y+.5*(boundsH-font.Height())), fontName, textColor, b.Text)
|
||||
fontName := b.FontName(ctx)
|
||||
font := ctx.Fonts().Font(fontName)
|
||||
ctx.Renderer().Text(font, geom.PtF32(pos.X, pos.Y+.5*(boundsH-font.Height())), textColor, b.Text)
|
||||
}
|
||||
|
||||
if b.Type == ButtonTypeOutlined {
|
||||
|
@ -25,7 +25,7 @@ func BuildCheckbox(text string, fn func(c *Checkbox)) *Checkbox {
|
||||
|
||||
func (c *Checkbox) desiredSize(ctx Context) geom.PointF32 {
|
||||
var pad = ctx.Style().Dimensions.TextPadding
|
||||
var font = ctx.Renderer().Font(c.FontName(ctx))
|
||||
var font = ctx.Fonts().Font(c.FontName(ctx))
|
||||
var w, h float32 = 0, font.Height()
|
||||
if len(c.Text) != 0 {
|
||||
w += pad + font.WidthOf(c.Text)
|
||||
@ -128,7 +128,7 @@ func (c *Checkbox) Render(ctx Context) {
|
||||
}
|
||||
if len(c.Text) != 0 {
|
||||
var fontName = c.FontName(ctx)
|
||||
var font = ctx.Renderer().Font(fontName)
|
||||
ctx.Renderer().Text(geom.PtF32(pos.X, pos.Y+.5*(boundsH-font.Height())), fontName, fore, c.Text)
|
||||
var font = ctx.Fonts().Font(fontName)
|
||||
ctx.Renderer().Text(font, geom.PtF32(pos.X, pos.Y+.5*(boundsH-font.Height())), fore, c.Text)
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package ui
|
||||
|
||||
type Context interface {
|
||||
Animate()
|
||||
Fonts() *Fonts
|
||||
HasQuit() bool
|
||||
Quit()
|
||||
Renderer() Renderer
|
||||
@ -15,14 +16,32 @@ var _ EventTarget = &context{}
|
||||
type context struct {
|
||||
animate bool
|
||||
quit chan struct{}
|
||||
r Renderer
|
||||
renderer Renderer
|
||||
view Control
|
||||
fonts *Fonts
|
||||
textures *Textures
|
||||
style *Style
|
||||
}
|
||||
|
||||
func newContext(r Renderer, s *Style, view Control) *context {
|
||||
return &context{
|
||||
quit: make(chan struct{}),
|
||||
renderer: r,
|
||||
style: s,
|
||||
view: view,
|
||||
fonts: NewFonts(r),
|
||||
textures: NewTextures(r)}
|
||||
}
|
||||
|
||||
func (c *context) Animate() { c.animate = true }
|
||||
|
||||
func (c *context) Destroy() {
|
||||
c.fonts.Destroy()
|
||||
c.textures.Destroy()
|
||||
}
|
||||
|
||||
func (c *context) Fonts() *Fonts { return c.fonts }
|
||||
|
||||
func (c *context) HasQuit() bool {
|
||||
select {
|
||||
case <-c.quit:
|
||||
@ -32,7 +51,7 @@ func (c *context) HasQuit() bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *context) Renderer() Renderer { return c.r }
|
||||
func (c *context) Renderer() Renderer { return c.renderer }
|
||||
|
||||
func (c *context) Style() *Style { return c.style }
|
||||
|
||||
|
@ -16,7 +16,12 @@ type basic struct {
|
||||
}
|
||||
|
||||
func (b *basic) Init(ctx ui.Context) error {
|
||||
_, err := ctx.Textures().CreateTexturePath("plus", "../resources/images/plus.png", true)
|
||||
_, err := ctx.Fonts().CreateFontPath("default", "../resources/font/OpenSans-Regular.ttf", 14)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = ctx.Textures().CreateTexturePath("plus", "../resources/images/plus.png", true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -73,11 +78,6 @@ func run() error {
|
||||
}
|
||||
defer render.Destroy()
|
||||
|
||||
err = render.RegisterFont("default", "../resources/font/OpenSans-Regular.ttf", 14)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ui.RunWait(render, ui.DefaultStyle(), &basic{}, true)
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
)
|
||||
|
||||
type Font interface {
|
||||
Destroy() error
|
||||
Height() float32
|
||||
Measure(t string) geom.RectangleF32
|
||||
WidthOf(t string) float32
|
||||
|
70
ui/fonts.go
Normal file
70
ui/fonts.go
Normal file
@ -0,0 +1,70 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
|
||||
"opslag.de/schobers/geom"
|
||||
)
|
||||
|
||||
type Fonts struct {
|
||||
render Renderer
|
||||
fonts map[string]Font
|
||||
}
|
||||
|
||||
func NewFonts(render Renderer) *Fonts {
|
||||
return &Fonts{render, map[string]Font{}}
|
||||
}
|
||||
|
||||
func (f *Fonts) AddFont(name string, font Font) {
|
||||
curr := f.fonts[name]
|
||||
if curr != nil {
|
||||
curr.Destroy()
|
||||
}
|
||||
f.fonts[name] = font
|
||||
}
|
||||
|
||||
func (f *Fonts) createFont(name string, create func() (Font, error)) (Font, error) {
|
||||
font, err := create()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.AddFont(name, font)
|
||||
return font, nil
|
||||
}
|
||||
|
||||
func (f *Fonts) CreateFontPath(name, path string, size int) (Font, error) {
|
||||
return f.createFont(name, func() (Font, error) {
|
||||
return f.render.CreateFontPath(path, size)
|
||||
})
|
||||
}
|
||||
|
||||
func (f *Fonts) Destroy() {
|
||||
for _, font := range f.fonts {
|
||||
font.Destroy()
|
||||
}
|
||||
f.fonts = nil
|
||||
}
|
||||
|
||||
func (f *Fonts) Font(name string) Font {
|
||||
font, ok := f.fonts[name]
|
||||
if ok {
|
||||
return font
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Fonts) Text(fontName string, p geom.PointF32, color color.Color, text string) {
|
||||
font := f.Font(fontName)
|
||||
if font == nil {
|
||||
return
|
||||
}
|
||||
f.render.Text(font, p, color, text)
|
||||
}
|
||||
|
||||
func (f *Fonts) TextAlign(fontName string, p geom.PointF32, color color.Color, text string, align HorizontalAlignment) {
|
||||
font := f.Font(fontName)
|
||||
if font == nil {
|
||||
return
|
||||
}
|
||||
f.render.TextAlign(font, p, color, text, align)
|
||||
}
|
12
ui/label.go
12
ui/label.go
@ -35,7 +35,7 @@ func (l *Label) hashContent(ctx Context) string {
|
||||
|
||||
func (l *Label) desiredSize(ctx Context) interface{} {
|
||||
fontName := l.FontName(ctx)
|
||||
font := ctx.Renderer().Font(fontName)
|
||||
font := ctx.Fonts().Font(fontName)
|
||||
width := font.WidthOf(l.Text)
|
||||
height := font.Height()
|
||||
pad := ctx.Style().Dimensions.TextPadding
|
||||
@ -49,16 +49,16 @@ func (l *Label) DesiredSize(ctx Context) geom.PointF32 {
|
||||
|
||||
func (l *Label) Render(ctx Context) {
|
||||
l.RenderBackground(ctx)
|
||||
c := l.FontColor(ctx)
|
||||
f := l.FontName(ctx)
|
||||
fontColor := l.FontColor(ctx)
|
||||
fontName := l.FontName(ctx)
|
||||
pad := ctx.Style().Dimensions.TextPadding
|
||||
bounds := l.bounds.Inset(pad)
|
||||
switch l.TextAlignment {
|
||||
case AlignLeft:
|
||||
ctx.Renderer().TextAlign(bounds.Min, f, c, l.Text, l.TextAlignment)
|
||||
ctx.Fonts().TextAlign(fontName, bounds.Min, fontColor, l.Text, l.TextAlignment)
|
||||
case AlignRight:
|
||||
ctx.Renderer().TextAlign(geom.PtF32(bounds.Max.X, bounds.Min.Y), f, c, l.Text, l.TextAlignment)
|
||||
ctx.Fonts().TextAlign(fontName, geom.PtF32(bounds.Max.X, bounds.Min.Y), fontColor, l.Text, l.TextAlignment)
|
||||
case AlignCenter:
|
||||
ctx.Renderer().TextAlign(geom.PtF32(.5*(bounds.Min.X+bounds.Max.X), bounds.Min.Y), f, c, l.Text, l.TextAlignment)
|
||||
ctx.Fonts().TextAlign(fontName, geom.PtF32(.5*(bounds.Min.X+bounds.Max.X), bounds.Min.Y), fontColor, l.Text, l.TextAlignment)
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ type Renderer interface {
|
||||
|
||||
// Drawing
|
||||
Clear(c color.Color)
|
||||
CreateFontPath(path string, size int) (Font, error)
|
||||
CreateTexture(m ImageSource) (Texture, error)
|
||||
CreateTextureGo(m image.Image, source bool) (Texture, error)
|
||||
CreateTexturePath(path string, source bool) (Texture, error)
|
||||
@ -25,16 +26,14 @@ type Renderer interface {
|
||||
DrawTexture(t Texture, p geom.PointF32)
|
||||
DrawTextureOptions(t Texture, p geom.PointF32, opts DrawOptions)
|
||||
FillRectangle(r geom.RectangleF32, c color.Color)
|
||||
Font(name string) Font
|
||||
Rectangle(r geom.RectangleF32, c color.Color, thickness float32)
|
||||
RegisterFont(name, path string, size int) error
|
||||
RenderTo(Texture)
|
||||
RenderToDisplay()
|
||||
SetMouseCursor(c MouseCursor)
|
||||
Size() geom.PointF32
|
||||
Target() Texture
|
||||
Text(p geom.PointF32, font string, color color.Color, text string)
|
||||
TextAlign(p geom.PointF32, font string, color color.Color, text string, align HorizontalAlignment)
|
||||
Text(font Font, p geom.PointF32, color color.Color, text string)
|
||||
TextAlign(font Font, p geom.PointF32, color color.Color, text string, align HorizontalAlignment)
|
||||
|
||||
// Resources
|
||||
Resources() Resources
|
||||
|
@ -2,6 +2,7 @@ package ui
|
||||
|
||||
import (
|
||||
"opslag.de/schobers/geom"
|
||||
"opslag.de/schobers/zntg"
|
||||
)
|
||||
|
||||
type Scrollbar struct {
|
||||
@ -55,7 +56,7 @@ func (s *Scrollbar) Handle(ctx Context, e Event) {
|
||||
}
|
||||
|
||||
func (s *Scrollbar) Render(ctx Context) {
|
||||
ctx.Renderer().FillRectangle(s.bounds, RGBA(0, 0, 0, 1))
|
||||
ctx.Renderer().FillRectangle(s.bounds, zntg.RGBA(0, 0, 0, 1))
|
||||
s.handle.Render(ctx)
|
||||
}
|
||||
|
||||
|
72
ui/style.go
72
ui/style.go
@ -1,6 +1,10 @@
|
||||
package ui
|
||||
|
||||
import "image/color"
|
||||
import (
|
||||
"image/color"
|
||||
|
||||
"opslag.de/schobers/zntg"
|
||||
)
|
||||
|
||||
var defaultDimensions *Dimensions
|
||||
var defaultFonts *Fonts
|
||||
@ -13,7 +17,7 @@ type Dimensions struct {
|
||||
TextPadding float32
|
||||
}
|
||||
|
||||
type Fonts struct {
|
||||
type FontNames struct {
|
||||
Default string
|
||||
}
|
||||
|
||||
@ -44,60 +48,44 @@ type Palette struct {
|
||||
|
||||
type Style struct {
|
||||
Dimensions *Dimensions
|
||||
Fonts *Fonts
|
||||
Fonts *FontNames
|
||||
Palette *Palette
|
||||
}
|
||||
|
||||
func DefaultDimensions() *Dimensions {
|
||||
if defaultDimensions == nil {
|
||||
defaultDimensions = &Dimensions{
|
||||
OutlineWidth: 2.,
|
||||
ScrollbarWidth: 16.,
|
||||
TextPadding: 8.,
|
||||
}
|
||||
return &Dimensions{
|
||||
OutlineWidth: 2.,
|
||||
ScrollbarWidth: 16.,
|
||||
TextPadding: 8.,
|
||||
}
|
||||
return defaultDimensions
|
||||
}
|
||||
|
||||
func DefaultFonts() *Fonts {
|
||||
if defaultFonts == nil {
|
||||
defaultFonts = &Fonts{
|
||||
Default: "default",
|
||||
}
|
||||
func DefaultFontNames() *FontNames {
|
||||
return &FontNames{
|
||||
Default: "default",
|
||||
}
|
||||
return defaultFonts
|
||||
}
|
||||
|
||||
func DefaultPalette() *Palette {
|
||||
if defaultPalette == nil {
|
||||
defaultPalette = &Palette{
|
||||
Background: color.White,
|
||||
Primary: RGBA(0x3F, 0x51, 0xB5, 0xFF),
|
||||
PrimaryDark: RGBA(0x00, 0x28, 0x84, 0xFF),
|
||||
PrimaryHighlight: RGBA(0xE8, 0xEA, 0xF6, 0xFF),
|
||||
PrimaryLight: RGBA(0x75, 0x7C, 0xE8, 0xFF),
|
||||
ShadedBackground: RGBA(0xFA, 0xFA, 0xFA, 0xFF),
|
||||
Text: color.Black,
|
||||
TextDisabled: RGBA(0xBD, 0xBD, 0xBD, 0xFF),
|
||||
TextNegative: RGBA(0xFF, 0x43, 0x36, 0xFF),
|
||||
TextOnPrimary: color.White,
|
||||
TextPositive: RGBA(0x4C, 0xAF, 0x50, 0xFF),
|
||||
}
|
||||
return &Palette{
|
||||
Background: color.White,
|
||||
Primary: zntg.MustHexColor(`#3F51B5`),
|
||||
PrimaryDark: zntg.MustHexColor(`#002884`),
|
||||
PrimaryHighlight: zntg.MustHexColor(`#E8EAF6`),
|
||||
PrimaryLight: zntg.MustHexColor(`#757CE8`),
|
||||
ShadedBackground: zntg.MustHexColor(`#FAFAFA`),
|
||||
Text: color.Black,
|
||||
TextDisabled: zntg.MustHexColor(`#BDBDBD`),
|
||||
TextNegative: zntg.MustHexColor(`#FF4336`),
|
||||
TextOnPrimary: color.White,
|
||||
TextPositive: zntg.MustHexColor(`#4CAF50`),
|
||||
}
|
||||
return defaultPalette
|
||||
}
|
||||
|
||||
func DefaultStyle() *Style {
|
||||
if defaultStyle == nil {
|
||||
defaultStyle = &Style{
|
||||
Dimensions: DefaultDimensions(),
|
||||
Fonts: DefaultFonts(),
|
||||
Palette: DefaultPalette(),
|
||||
}
|
||||
return &Style{
|
||||
Dimensions: DefaultDimensions(),
|
||||
Fonts: DefaultFontNames(),
|
||||
Palette: DefaultPalette(),
|
||||
}
|
||||
return defaultStyle
|
||||
}
|
||||
|
||||
func RGBA(r, g, b, a byte) *color.RGBA {
|
||||
return &color.RGBA{R: r, G: g, B: b, A: a}
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ func (b *TextBox) Arrange(ctx Context, bounds geom.RectangleF32, offset geom.Poi
|
||||
|
||||
func (b *TextBox) DesiredSize(ctx Context) geom.PointF32 {
|
||||
var fontName = b.FontName(ctx)
|
||||
var font = ctx.Renderer().Font(fontName)
|
||||
var font = ctx.Fonts().Font(fontName)
|
||||
var width = font.WidthOf(b.Text)
|
||||
var height = font.Height()
|
||||
var pad = b.pad(ctx)
|
||||
@ -68,7 +68,7 @@ func (b *TextBox) DesiredSize(ctx Context) geom.PointF32 {
|
||||
func (b *TextBox) mousePosToCaretPos(ctx Context, e MouseEvent) int {
|
||||
p := b.ToControlPosition(e.Pos())
|
||||
offset := p.X - b.box.bounds.Min.X
|
||||
f := ctx.Renderer().Font(b.FontName(ctx))
|
||||
f := ctx.Fonts().Font(b.FontName(ctx))
|
||||
var carets = [3]int{0, 0, len(b.Text)}
|
||||
var offsets = [3]float32{0, 0, f.WidthOf(b.Text)}
|
||||
var updateCenter = func() {
|
||||
@ -234,7 +234,6 @@ func (b *TextBox) Render(ctx Context) {
|
||||
b.RenderOutline(ctx)
|
||||
|
||||
c := b.FontColor(ctx)
|
||||
f := b.FontName(ctx)
|
||||
style := ctx.Style()
|
||||
var caretWidth float32 = 1
|
||||
b.box.RenderFn(ctx, func(_ Context, size geom.PointF32) {
|
||||
@ -244,14 +243,16 @@ func (b *TextBox) Render(ctx Context) {
|
||||
back = ctx.Style().Palette.Background
|
||||
}
|
||||
renderer.Clear(back)
|
||||
fontName := b.FontName(ctx)
|
||||
font := ctx.Fonts().Font(fontName)
|
||||
if b.Selection.Start != b.Selection.End {
|
||||
left, right := renderer.Font(f).WidthOf(b.Text[:b.Selection.Start]), renderer.Font(f).WidthOf(b.Text[:b.Selection.End])
|
||||
left, right := font.WidthOf(b.Text[:b.Selection.Start]), font.WidthOf(b.Text[:b.Selection.End])
|
||||
renderer.FillRectangle(geom.RectF32(left, 0, right, size.Y), style.Palette.PrimaryHighlight)
|
||||
}
|
||||
renderer.Text(geom.ZeroPtF32, f, c, b.Text)
|
||||
renderer.Text(font, geom.ZeroPtF32, c, b.Text)
|
||||
const interval = 500 * time.Millisecond
|
||||
if b.Focus && (time.Since(b.blink)/interval)%2 == 0 {
|
||||
var w = renderer.Font(f).WidthOf(b.Text[:b.Selection.Caret])
|
||||
var w = font.WidthOf(b.Text[:b.Selection.Caret])
|
||||
var caret = w + .5*caretWidth
|
||||
renderer.Rectangle(geom.RectF32(caret, 0, caret, size.Y), c, caretWidth)
|
||||
}
|
||||
|
4
ui/ui.go
4
ui/ui.go
@ -13,7 +13,9 @@ func Run(r Renderer, s *Style, view Control) error {
|
||||
|
||||
// RunWait runs the application loop and conditionally waits on events before rendering.
|
||||
func RunWait(r Renderer, s *Style, view Control, wait bool) error {
|
||||
ctx := &context{quit: make(chan struct{}), r: r, style: s, view: view, textures: NewTextures(r)}
|
||||
ctx := newContext(r, s, view)
|
||||
defer ctx.Destroy()
|
||||
|
||||
root, ok := view.(RootControl)
|
||||
if ok {
|
||||
err := root.Init(ctx)
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"image/color"
|
||||
|
||||
"opslag.de/schobers/geom"
|
||||
"opslag.de/schobers/zntg"
|
||||
)
|
||||
|
||||
func Background(content Control, c color.Color) Control {
|
||||
@ -37,7 +38,7 @@ type shadow struct {
|
||||
func (s *shadow) Render(ctx Context) {
|
||||
s.Proxy.Render(ctx)
|
||||
b := s.Bounds()
|
||||
shadow := RGBA(0xBD, 0xBD, 0xBD, 0x2F)
|
||||
shadow := zntg.RGBA(0xBD, 0xBD, 0xBD, 0x2F)
|
||||
ctx.Renderer().FillRectangle(geom.RectF32(b.Min.X, b.Min.Y, b.Max.X, b.Min.Y+3), shadow)
|
||||
ctx.Renderer().FillRectangle(geom.RectF32(b.Min.X, b.Min.Y, b.Max.X, b.Min.Y+2), shadow)
|
||||
ctx.Renderer().FillRectangle(geom.RectF32(b.Min.X, b.Min.Y, b.Max.X, b.Min.Y+1), shadow)
|
||||
|
Loading…
Reference in New Issue
Block a user