messeji/inputfield.go

132 lines
3.2 KiB
Go

package messeji
import (
"sync"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/inpututil"
"golang.org/x/image/font"
)
// InputField is a text input field. Call Update and Draw when your Game's
// Update and Draw methods are called.
//
// Note: A position and size must be set via SetRect before the field will appear.
// Keyboard events are not handled by default, and may be enabled via SetHandleKeyboard.
type InputField struct {
*TextField
// changedFunc is a function which is called when the text buffer is changed.
// The function may return false to skip adding the rune to the text buffer.
changedFunc func(r rune) (accept bool)
// selectedFunc is a function which is called when the enter key is pressed. The
// function may return true to clear the text buffer.
selectedFunc func() (accept bool)
// readBuffer is where incoming runes are stored before being added to the input buffer.
readBuffer []rune
sync.Mutex
}
// NewInputField returns a new InputField. See type documentation for more info.
func NewInputField(face font.Face) *InputField {
f := &InputField{
TextField: NewTextField(face),
}
f.TextField.suffix = "_"
return f
}
// SetHandleKeyboard sets a flag controlling whether keyboard input should be handled
// by the field. This can be used to facilitate focus changes between multiple inputs.
func (f *InputField) SetHandleKeyboard(handle bool) {
f.Lock()
defer f.Unlock()
f.handleKeyboard = handle
// Show or hide cursor.
if f.handleKeyboard {
f.TextField.suffix = "_"
} else {
f.TextField.suffix = ""
}
}
// SetChangedFunc sets a handler which is called when the text buffer is changed.
// The handler may return true to add the rune to the text buffer.
func (f *InputField) SetChangedFunc(changedFunc func(r rune) (accept bool)) {
f.changedFunc = changedFunc
}
// SetSelectedFunc sets a handler which is called when the enter key is pressed.
// Providing a nil function value will remove the existing handler (if set).
// The handler may return true to clear the text buffer.
func (f *InputField) SetSelectedFunc(selectedFunc func() (accept bool)) {
f.selectedFunc = selectedFunc
}
// Update updates the input field. This function should be called when
// Game.Update is called.
func (f *InputField) Update() error {
f.Lock()
defer f.Unlock()
if !f.visible || rectIsZero(f.r) {
return nil
}
if !f.handleKeyboard {
return f.TextField.Update()
}
var redraw bool
f.readBuffer = ebiten.AppendInputChars(f.readBuffer[:0])
for _, r := range f.readBuffer {
if f.changedFunc != nil {
f.Unlock()
accept := f.changedFunc(r)
f.Lock()
if !accept {
continue
}
}
f.buffer += string(r)
redraw = true
}
if inpututil.IsKeyJustPressed(ebiten.KeyBackspace) && len(f.buffer) > 0 {
f.buffer = f.buffer[:len(f.buffer)-1]
redraw = true
}
if inpututil.IsKeyJustPressed(ebiten.KeyEnter) || inpututil.IsKeyJustPressed(ebiten.KeyKPEnter) {
if f.selectedFunc != nil {
f.Unlock()
accept := f.selectedFunc()
f.Lock()
// Clear input buffer.
if accept {
f.buffer = ""
redraw = true
}
} else if !f.singleLine {
// Append newline.
f.buffer += "\n"
redraw = true
}
}
if redraw {
f.bufferModified()
}
return f.TextField.Update()
}