Resize font to fit button label, add Text.SetAutoResize to allow fitting text within field
This commit is contained in:
parent
c1f1fe1adb
commit
4c67a3c448
4 changed files with 121 additions and 23 deletions
35
button.go
35
button.go
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"code.rocket9labs.com/tslocum/etk/messeji"
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
"golang.org/x/image/font"
|
||||
"golang.org/x/image/font/sfnt"
|
||||
)
|
||||
|
||||
|
@ -13,6 +14,9 @@ import (
|
|||
type Button struct {
|
||||
*Box
|
||||
field *messeji.TextField
|
||||
textFont *sfnt.Font
|
||||
textSize int
|
||||
textAutoSize int
|
||||
borderSize int
|
||||
borderTop color.RGBA
|
||||
borderRight color.RGBA
|
||||
|
@ -38,6 +42,8 @@ func NewButton(label string, onSelected func() error) *Button {
|
|||
b := &Button{
|
||||
Box: NewBox(),
|
||||
field: f,
|
||||
textFont: Style.TextFont,
|
||||
textSize: Scale(Style.TextSize),
|
||||
onSelected: onSelected,
|
||||
borderSize: Scale(Style.BorderSize),
|
||||
borderTop: Style.BorderColorTop,
|
||||
|
@ -46,6 +52,7 @@ func NewButton(label string, onSelected func() error) *Button {
|
|||
borderLeft: Style.BorderColorLeft,
|
||||
}
|
||||
b.SetBackground(Style.ButtonBgColor)
|
||||
b.resizeFont()
|
||||
return b
|
||||
}
|
||||
|
||||
|
@ -54,6 +61,7 @@ func (b *Button) SetRect(r image.Rectangle) {
|
|||
b.Box.rect = r
|
||||
|
||||
b.field.SetRect(r)
|
||||
b.resizeFont()
|
||||
|
||||
for _, w := range b.children {
|
||||
w.SetRect(r)
|
||||
|
@ -93,6 +101,7 @@ func (b *Button) SetText(text string) {
|
|||
defer b.Unlock()
|
||||
|
||||
b.field.SetText(text)
|
||||
b.resizeFont()
|
||||
}
|
||||
|
||||
// SetFont sets the font and text size of button label. Scaling is not applied.
|
||||
|
@ -100,7 +109,31 @@ func (b *Button) SetFont(fnt *sfnt.Font, size int) {
|
|||
b.Lock()
|
||||
defer b.Unlock()
|
||||
|
||||
b.field.SetFont(FontFace(fnt, size), fontMutex)
|
||||
b.textFont, b.textSize = fnt, size
|
||||
b.resizeFont()
|
||||
}
|
||||
|
||||
func (b *Button) resizeFont() {
|
||||
w := b.rect.Dx() - b.field.Padding()*2
|
||||
if w == 0 {
|
||||
b.textAutoSize = b.textSize
|
||||
return
|
||||
}
|
||||
|
||||
var autoSize int
|
||||
var ff font.Face
|
||||
for autoSize = b.textSize; autoSize > 0; autoSize-- {
|
||||
ff = FontFace(b.textFont, autoSize)
|
||||
if BoundString(ff, b.field.Text()).Dx() <= w {
|
||||
break
|
||||
}
|
||||
}
|
||||
if b.textAutoSize == autoSize {
|
||||
return
|
||||
}
|
||||
|
||||
b.field.SetFont(ff, fontMutex)
|
||||
b.textAutoSize = autoSize
|
||||
}
|
||||
|
||||
// SetHorizontal sets the horizontal alignment of the button label.
|
||||
|
|
10
go.mod
10
go.mod
|
@ -5,16 +5,16 @@ go 1.18
|
|||
require (
|
||||
github.com/hajimehoshi/ebiten/v2 v2.7.8
|
||||
github.com/llgcode/draw2d v0.0.0-20240627062922-0ed1ff131195
|
||||
golang.org/x/image v0.18.0
|
||||
golang.org/x/image v0.19.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/ebitengine/gomobile v0.0.0-20240518074828-e86332849895 // indirect
|
||||
github.com/ebitengine/gomobile v0.0.0-20240802043200-192f051f4fcc // indirect
|
||||
github.com/ebitengine/hideconsole v1.0.0 // indirect
|
||||
github.com/ebitengine/purego v0.7.1 // indirect
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||
github.com/jezek/xgb v1.1.1 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/sys v0.22.0 // indirect
|
||||
golang.org/x/text v0.16.0 // indirect
|
||||
golang.org/x/sync v0.8.0 // indirect
|
||||
golang.org/x/sys v0.24.0 // indirect
|
||||
golang.org/x/text v0.17.0 // indirect
|
||||
)
|
||||
|
|
20
go.sum
20
go.sum
|
@ -1,5 +1,5 @@
|
|||
github.com/ebitengine/gomobile v0.0.0-20240518074828-e86332849895 h1:48bCqKTuD7Z0UovDfvpCn7wZ0GUZ+yosIteNDthn3FU=
|
||||
github.com/ebitengine/gomobile v0.0.0-20240518074828-e86332849895/go.mod h1:XZdLv05c5hOZm3fM2NlJ92FyEZjnslcMcNRrhxs8+8M=
|
||||
github.com/ebitengine/gomobile v0.0.0-20240802043200-192f051f4fcc h1:76TYsaP1F48tiQRlrr71NsbfxBcFM9/8bEHS9/JbsQg=
|
||||
github.com/ebitengine/gomobile v0.0.0-20240802043200-192f051f4fcc/go.mod h1:RM/c3pvru6dRqgGEW7RCTb6czFXYAa3MxbXu3u8/dcI=
|
||||
github.com/ebitengine/hideconsole v1.0.0 h1:5J4U0kXF+pv/DhiXt5/lTz0eO5ogJ1iXb8Yj1yReDqE=
|
||||
github.com/ebitengine/hideconsole v1.0.0/go.mod h1:hTTBTvVYWKBuxPr7peweneWdkUwEuHuB3C1R/ielR1A=
|
||||
github.com/ebitengine/purego v0.7.1 h1:6/55d26lG3o9VCZX8lping+bZcmShseiqlh2bnUDiPA=
|
||||
|
@ -14,11 +14,11 @@ github.com/jezek/xgb v1.1.1/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFl
|
|||
github.com/llgcode/draw2d v0.0.0-20240627062922-0ed1ff131195 h1:Vdz2cBh5Fw2MYHWi3ED2PraDQaWEUhNCr1XFHrP4N5A=
|
||||
github.com/llgcode/draw2d v0.0.0-20240627062922-0ed1ff131195/go.mod h1:1Vk0LDW6jG5cGc2D9RQUxHaE0vYhTvIwSo9mOL6K4/U=
|
||||
github.com/llgcode/ps v0.0.0-20210114104736-f4b0c5d1e02e h1:ZAvbj5hI/G/EbAYAcj4yCXUNiFKefEhH0qfImDDD0/8=
|
||||
golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ=
|
||||
golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/image v0.19.0 h1:D9FX4QWkLfkeqaC62SonffIIuYdOk/UE2XKUBgRIBIQ=
|
||||
golang.org/x/image v0.19.0/go.mod h1:y0zrRqlQRWQ5PXaYCOMLTW2fpsxZ8Qh9I/ohnInJEys=
|
||||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
|
||||
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
|
||||
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
|
|
79
text.go
79
text.go
|
@ -6,14 +6,19 @@ import (
|
|||
|
||||
"code.rocket9labs.com/tslocum/etk/messeji"
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
"golang.org/x/image/font"
|
||||
"golang.org/x/image/font/sfnt"
|
||||
)
|
||||
|
||||
// Text is a text display widget.
|
||||
type Text struct {
|
||||
*Box
|
||||
field *messeji.TextField
|
||||
children []Widget
|
||||
field *messeji.TextField
|
||||
textFont *sfnt.Font
|
||||
textSize int
|
||||
textResize bool
|
||||
textAutoSize int
|
||||
children []Widget
|
||||
}
|
||||
|
||||
// NewText returns a new Text widget.
|
||||
|
@ -23,10 +28,14 @@ func NewText(text string) *Text {
|
|||
f.SetForegroundColor(Style.TextColorLight)
|
||||
f.SetHandleKeyboard(true)
|
||||
|
||||
return &Text{
|
||||
Box: NewBox(),
|
||||
field: f,
|
||||
t := &Text{
|
||||
Box: NewBox(),
|
||||
field: f,
|
||||
textFont: Style.TextFont,
|
||||
textSize: Scale(Style.TextSize),
|
||||
}
|
||||
t.resizeFont()
|
||||
return t
|
||||
}
|
||||
|
||||
// SetRect sets the position and size of the widget.
|
||||
|
@ -36,6 +45,7 @@ func (t *Text) SetRect(r image.Rectangle) {
|
|||
|
||||
t.rect = r
|
||||
t.field.SetRect(r)
|
||||
t.resizeFont()
|
||||
}
|
||||
|
||||
// Foreground return the color of the text within the field.
|
||||
|
@ -118,7 +128,12 @@ func (t *Text) Write(p []byte) (n int, err error) {
|
|||
t.Lock()
|
||||
defer t.Unlock()
|
||||
|
||||
return t.field.Write(p)
|
||||
n, err = t.field.Write(p)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
t.resizeFont()
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Text returns the content of the text buffer.
|
||||
|
@ -135,6 +150,45 @@ func (t *Text) SetText(text string) {
|
|||
defer t.Unlock()
|
||||
|
||||
t.field.SetText(text)
|
||||
t.resizeFont()
|
||||
}
|
||||
|
||||
func (t *Text) resizeFont() {
|
||||
if !t.textResize {
|
||||
if t.textAutoSize == t.textSize {
|
||||
return
|
||||
}
|
||||
t.textAutoSize = t.textSize
|
||||
ff := FontFace(t.textFont, t.textSize)
|
||||
t.field.SetFont(ff, fontMutex)
|
||||
return
|
||||
}
|
||||
|
||||
w := t.rect.Dx() - t.field.Padding()*2
|
||||
if w == 0 {
|
||||
if t.textAutoSize == t.textSize {
|
||||
return
|
||||
}
|
||||
t.textAutoSize = t.textSize
|
||||
ff := FontFace(t.textFont, t.textSize)
|
||||
t.field.SetFont(ff, fontMutex)
|
||||
return
|
||||
}
|
||||
|
||||
var autoSize int
|
||||
var ff font.Face
|
||||
for autoSize = t.textSize; autoSize > 0; autoSize-- {
|
||||
ff = FontFace(t.textFont, autoSize)
|
||||
if BoundString(ff, t.field.Text()).Dx() <= w {
|
||||
break
|
||||
}
|
||||
}
|
||||
if t.textAutoSize == autoSize {
|
||||
return
|
||||
}
|
||||
|
||||
t.field.SetFont(ff, fontMutex)
|
||||
t.textAutoSize = autoSize
|
||||
}
|
||||
|
||||
// SetScrollBarVisible sets whether the scroll bar is visible on the screen.
|
||||
|
@ -159,7 +213,18 @@ func (t *Text) SetFont(fnt *sfnt.Font, size int) {
|
|||
t.Lock()
|
||||
defer t.Unlock()
|
||||
|
||||
t.field.SetFont(FontFace(fnt, size), fontMutex)
|
||||
t.textFont, t.textSize = fnt, size
|
||||
t.resizeFont()
|
||||
}
|
||||
|
||||
// SetAutoResize sets whether the font is automatically scaled down when it is
|
||||
// too large to fit the entire text buffer on one line.
|
||||
func (t *Text) SetAutoResize(resize bool) {
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
|
||||
t.textResize = resize
|
||||
t.resizeFont()
|
||||
}
|
||||
|
||||
// Padding returns the amount of padding around the text within the field.
|
||||
|
|
Loading…
Reference in a new issue