2022-03-10 05:19:04 +00:00
|
|
|
package messeji
|
|
|
|
|
|
|
|
import (
|
2022-07-07 21:41:15 +00:00
|
|
|
"sync"
|
|
|
|
|
2022-03-10 05:19:04 +00:00
|
|
|
"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
|
2022-06-10 01:12:08 +00:00
|
|
|
// function may return true to clear the text buffer.
|
2022-03-10 05:19:04 +00:00
|
|
|
selectedFunc func() (accept bool)
|
|
|
|
|
|
|
|
// readBuffer is where incoming runes are stored before being added to the input buffer.
|
|
|
|
readBuffer []rune
|
2022-07-07 21:41:15 +00:00
|
|
|
|
2023-10-22 19:24:19 +00:00
|
|
|
// keyBuffer is where incoming keys are stored before being added to the input buffer.
|
|
|
|
keyBuffer []ebiten.Key
|
|
|
|
|
|
|
|
// rawRuneBuffer is where incoming raw runes are stored before being added to the input buffer.
|
|
|
|
rawRuneBuffer []rune
|
|
|
|
|
|
|
|
// rawKeyBuffer is where incoming raw keys are stored before being added to the input buffer.
|
|
|
|
rawKeyBuffer []ebiten.Key
|
|
|
|
|
2022-07-07 21:41:15 +00:00
|
|
|
sync.Mutex
|
2022-03-10 05:19:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewInputField returns a new InputField. See type documentation for more info.
|
2023-11-08 01:35:08 +00:00
|
|
|
func NewInputField(face font.Face, faceMutex *sync.Mutex) *InputField {
|
2022-03-10 05:19:04 +00:00
|
|
|
f := &InputField{
|
2023-11-08 01:35:08 +00:00
|
|
|
TextField: NewTextField(face, faceMutex),
|
2022-03-10 05:19:04 +00:00
|
|
|
}
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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).
|
2022-06-10 01:12:08 +00:00
|
|
|
// The handler may return true to clear the text buffer.
|
2022-03-10 05:19:04 +00:00
|
|
|
func (f *InputField) SetSelectedFunc(selectedFunc func() (accept bool)) {
|
|
|
|
f.selectedFunc = selectedFunc
|
|
|
|
}
|
|
|
|
|
2024-01-09 20:51:05 +00:00
|
|
|
// HandleKeyboardEvent passes the provided key or rune to the Inputfield.
|
2023-10-27 23:49:30 +00:00
|
|
|
func (f *InputField) HandleKeyboardEvent(key ebiten.Key, r rune) (handled bool, err error) {
|
2022-03-10 05:19:04 +00:00
|
|
|
f.Lock()
|
2022-07-07 21:41:15 +00:00
|
|
|
defer f.Unlock()
|
2022-03-10 05:19:04 +00:00
|
|
|
|
|
|
|
if !f.visible || rectIsZero(f.r) {
|
2023-10-22 19:24:19 +00:00
|
|
|
return
|
2022-03-10 05:19:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if !f.handleKeyboard {
|
2023-10-22 19:24:19 +00:00
|
|
|
return
|
2022-03-10 05:19:04 +00:00
|
|
|
}
|
|
|
|
|
2023-10-22 19:24:19 +00:00
|
|
|
// Handle rune event.
|
2024-01-09 20:51:05 +00:00
|
|
|
if r > 0 {
|
2023-10-27 23:49:30 +00:00
|
|
|
f.handleRunes([]rune{r})
|
|
|
|
return true, nil
|
2023-10-22 19:24:19 +00:00
|
|
|
}
|
2022-03-10 05:19:04 +00:00
|
|
|
|
2023-10-22 19:24:19 +00:00
|
|
|
// Handle key event.
|
2023-10-27 23:49:30 +00:00
|
|
|
f.handleKeys([]ebiten.Key{key})
|
|
|
|
return true, nil
|
2023-10-22 19:24:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (f *InputField) handleRunes(runes []rune) bool {
|
|
|
|
var redraw bool
|
|
|
|
for _, r := range runes {
|
2022-03-10 05:19:04 +00:00
|
|
|
if f.changedFunc != nil {
|
|
|
|
f.Unlock()
|
|
|
|
accept := f.changedFunc(r)
|
|
|
|
f.Lock()
|
|
|
|
|
|
|
|
if !accept {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-27 23:49:30 +00:00
|
|
|
f.TextField._write([]byte(string(r)))
|
2022-03-10 05:19:04 +00:00
|
|
|
redraw = true
|
|
|
|
}
|
2023-10-27 23:49:30 +00:00
|
|
|
|
2023-10-22 19:24:19 +00:00
|
|
|
return redraw
|
|
|
|
}
|
2022-03-10 05:19:04 +00:00
|
|
|
|
2023-10-22 19:24:19 +00:00
|
|
|
func (f *InputField) handleKeys(keys []ebiten.Key) bool {
|
|
|
|
var redraw bool
|
|
|
|
for _, key := range keys {
|
|
|
|
switch key {
|
|
|
|
case ebiten.KeyBackspace:
|
2023-11-18 02:43:56 +00:00
|
|
|
l := len(f.buffer)
|
|
|
|
if l > 0 {
|
2023-11-23 02:20:58 +00:00
|
|
|
var rewrap bool
|
2023-11-18 02:43:56 +00:00
|
|
|
if len(f.incoming) != 0 {
|
|
|
|
line := string(f.incoming)
|
|
|
|
f.incoming = append(f.incoming, []byte(line[:len(line)-1])...)
|
|
|
|
} else if len(f.buffer[l-1]) == 0 {
|
|
|
|
f.buffer = f.buffer[:l-1]
|
2023-11-23 02:20:58 +00:00
|
|
|
rewrap = true
|
2023-11-18 02:43:56 +00:00
|
|
|
} else {
|
|
|
|
line := string(f.buffer[l-1])
|
|
|
|
f.buffer[l-1] = []byte(line[:len(line)-1])
|
2023-11-23 02:20:58 +00:00
|
|
|
rewrap = true
|
|
|
|
}
|
|
|
|
if rewrap && (f.needWrap == -1 || f.needWrap > l-1) {
|
|
|
|
f.needWrap = l - 1
|
2023-11-18 02:43:56 +00:00
|
|
|
}
|
2023-10-22 19:24:19 +00:00
|
|
|
redraw = true
|
2023-10-27 23:49:30 +00:00
|
|
|
f.modified = true
|
|
|
|
f.redraw = true
|
2023-10-22 19:24:19 +00:00
|
|
|
}
|
|
|
|
case ebiten.KeyEnter, ebiten.KeyKPEnter:
|
|
|
|
if f.selectedFunc != nil {
|
|
|
|
f.Unlock()
|
|
|
|
accept := f.selectedFunc()
|
|
|
|
f.Lock()
|
|
|
|
|
|
|
|
// Clear input buffer.
|
|
|
|
if accept {
|
2023-11-18 02:43:56 +00:00
|
|
|
f.incoming = f.incoming[:0]
|
2023-11-23 02:20:58 +00:00
|
|
|
f.buffer = f.buffer[:0]
|
|
|
|
f.bufferWrapped = f.bufferWrapped[:0]
|
|
|
|
f.lineWidths = f.lineWidths[:0]
|
|
|
|
f.needWrap = 0
|
2023-11-25 05:51:18 +00:00
|
|
|
f.wrapStart = 0
|
2023-10-27 23:49:30 +00:00
|
|
|
f.modified = true
|
|
|
|
f.redraw = true
|
2023-10-22 19:24:19 +00:00
|
|
|
redraw = true
|
|
|
|
}
|
|
|
|
} else if !f.singleLine {
|
|
|
|
// Append newline.
|
2023-11-18 02:43:56 +00:00
|
|
|
f.incoming = append(f.incoming, '\n')
|
2023-10-27 23:49:30 +00:00
|
|
|
f.modified = true
|
|
|
|
f.redraw = true
|
2022-06-10 01:12:08 +00:00
|
|
|
redraw = true
|
|
|
|
}
|
2022-03-10 05:19:04 +00:00
|
|
|
}
|
|
|
|
}
|
2023-10-22 19:24:19 +00:00
|
|
|
return redraw
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
|
|
|
// Handler rune input.
|
|
|
|
f.readBuffer = ebiten.AppendInputChars(f.readBuffer[:0])
|
|
|
|
if f.handleRunes(f.readBuffer) {
|
|
|
|
redraw = true
|
|
|
|
}
|
|
|
|
if f.handleRunes(f.rawRuneBuffer) {
|
|
|
|
redraw = true
|
|
|
|
}
|
|
|
|
f.rawRuneBuffer = f.rawRuneBuffer[:0]
|
|
|
|
|
2023-10-27 23:49:30 +00:00
|
|
|
// Handle key input.
|
2023-10-22 19:24:19 +00:00
|
|
|
f.keyBuffer = inpututil.AppendJustPressedKeys(f.keyBuffer[:0])
|
|
|
|
if f.handleKeys(f.keyBuffer) {
|
|
|
|
redraw = true
|
|
|
|
}
|
|
|
|
if f.handleKeys(f.rawKeyBuffer) {
|
|
|
|
redraw = true
|
|
|
|
}
|
|
|
|
f.rawKeyBuffer = f.rawKeyBuffer[:0]
|
2022-03-10 05:19:04 +00:00
|
|
|
|
|
|
|
if redraw {
|
|
|
|
f.bufferModified()
|
|
|
|
}
|
|
|
|
|
|
|
|
return f.TextField.Update()
|
|
|
|
}
|