...

Source file src/code.rocketnine.space/tslocum/messeji/inputfield.go

Documentation: code.rocketnine.space/tslocum/messeji

     1  package messeji
     2  
     3  import (
     4  	"sync"
     5  
     6  	"github.com/hajimehoshi/ebiten/v2"
     7  	"github.com/hajimehoshi/ebiten/v2/inpututil"
     8  	"golang.org/x/image/font"
     9  )
    10  
    11  // InputField is a text input field. Call Update and Draw when your Game's
    12  // Update and Draw methods are called.
    13  //
    14  // Note: A position and size must be set via SetRect before the field will appear.
    15  // Keyboard events are not handled by default, and may be enabled via SetHandleKeyboard.
    16  type InputField struct {
    17  	*TextField
    18  
    19  	// changedFunc is a function which is called when the text buffer is changed.
    20  	// The function may return false to skip adding the rune to the text buffer.
    21  	changedFunc func(r rune) (accept bool)
    22  
    23  	// selectedFunc is a function which is called when the enter key is pressed. The
    24  	// function may return true to clear the text buffer.
    25  	selectedFunc func() (accept bool)
    26  
    27  	// readBuffer is where incoming runes are stored before being added to the input buffer.
    28  	readBuffer []rune
    29  
    30  	sync.Mutex
    31  }
    32  
    33  // NewInputField returns a new InputField. See type documentation for more info.
    34  func NewInputField(face font.Face) *InputField {
    35  	f := &InputField{
    36  		TextField: NewTextField(face),
    37  	}
    38  	f.TextField.suffix = "_"
    39  	return f
    40  }
    41  
    42  // SetHandleKeyboard sets a flag controlling whether keyboard input should be handled
    43  // by the field. This can be used to facilitate focus changes between multiple inputs.
    44  func (f *InputField) SetHandleKeyboard(handle bool) {
    45  	f.Lock()
    46  	defer f.Unlock()
    47  
    48  	f.handleKeyboard = handle
    49  
    50  	// Show or hide cursor.
    51  	if f.handleKeyboard {
    52  		f.TextField.suffix = "_"
    53  	} else {
    54  		f.TextField.suffix = ""
    55  	}
    56  }
    57  
    58  // SetChangedFunc sets a handler which is called when the text buffer is changed.
    59  // The handler may return true to add the rune to the text buffer.
    60  func (f *InputField) SetChangedFunc(changedFunc func(r rune) (accept bool)) {
    61  	f.changedFunc = changedFunc
    62  }
    63  
    64  // SetSelectedFunc sets a handler which is called when the enter key is pressed.
    65  // Providing a nil function value will remove the existing handler (if set).
    66  // The handler may return true to clear the text buffer.
    67  func (f *InputField) SetSelectedFunc(selectedFunc func() (accept bool)) {
    68  	f.selectedFunc = selectedFunc
    69  }
    70  
    71  // Update updates the input field. This function should be called when
    72  // Game.Update is called.
    73  func (f *InputField) Update() error {
    74  	f.Lock()
    75  	defer f.Unlock()
    76  
    77  	if !f.visible || rectIsZero(f.r) {
    78  		return nil
    79  	}
    80  
    81  	if !f.handleKeyboard {
    82  		return f.TextField.Update()
    83  	}
    84  
    85  	var redraw bool
    86  
    87  	f.readBuffer = ebiten.AppendInputChars(f.readBuffer[:0])
    88  	for _, r := range f.readBuffer {
    89  		if f.changedFunc != nil {
    90  			f.Unlock()
    91  			accept := f.changedFunc(r)
    92  			f.Lock()
    93  
    94  			if !accept {
    95  				continue
    96  			}
    97  		}
    98  
    99  		f.buffer += string(r)
   100  		redraw = true
   101  	}
   102  
   103  	if inpututil.IsKeyJustPressed(ebiten.KeyBackspace) && len(f.buffer) > 0 {
   104  		f.buffer = f.buffer[:len(f.buffer)-1]
   105  		redraw = true
   106  	}
   107  
   108  	if inpututil.IsKeyJustPressed(ebiten.KeyEnter) || inpututil.IsKeyJustPressed(ebiten.KeyKPEnter) {
   109  		if f.selectedFunc != nil {
   110  			f.Unlock()
   111  			accept := f.selectedFunc()
   112  			f.Lock()
   113  
   114  			// Clear input buffer.
   115  			if accept {
   116  				f.buffer = ""
   117  				redraw = true
   118  			}
   119  		} else if !f.singleLine {
   120  			// Append newline.
   121  			f.buffer += "\n"
   122  			redraw = true
   123  		}
   124  	}
   125  
   126  	if redraw {
   127  		f.bufferModified()
   128  	}
   129  
   130  	return f.TextField.Update()
   131  }
   132  

View as plain text