...

Source file src/code.rocket9labs.com/tslocum/etk/input.go

Documentation: code.rocket9labs.com/tslocum/etk

     1  package etk
     2  
     3  import (
     4  	"image"
     5  	"image/color"
     6  
     7  	"code.rocket9labs.com/tslocum/etk/messeji"
     8  	"github.com/hajimehoshi/ebiten/v2"
     9  	"github.com/hajimehoshi/ebiten/v2/text/v2"
    10  )
    11  
    12  // Input is a text input widget. The Input widget is simply a Text widget that
    13  // also accepts user input.
    14  type Input struct {
    15  	*Box
    16  	field           *messeji.InputField
    17  	cursor          string
    18  	borderSize      int
    19  	borderFocused   color.RGBA
    20  	borderUnfocused color.RGBA
    21  	focus           bool
    22  }
    23  
    24  // NewInput returns a new Input widget.
    25  func NewInput(text string, onSelected func(text string) (handled bool)) *Input {
    26  	f := messeji.NewInputField(Style.TextFont, Scale(Style.TextSize), fontMutex)
    27  	f.SetForegroundColor(Style.TextColorLight)
    28  	f.SetBackgroundColor(transparent)
    29  	f.SetScrollBarColors(Style.ScrollAreaColor, Style.ScrollHandleColor)
    30  	f.SetScrollBorderSize(Scale(Style.ScrollBorderSize))
    31  	f.SetScrollBorderColors(Style.ScrollBorderTop, Style.ScrollBorderRight, Style.ScrollBorderBottom, Style.ScrollBorderLeft)
    32  	f.SetPrefix("")
    33  	f.SetSuffix("")
    34  	f.SetText(text)
    35  	f.SetHandleKeyboard(true)
    36  	f.SetSelectedFunc(func() (accept bool) {
    37  		return onSelected(f.Text())
    38  	})
    39  
    40  	i := &Input{
    41  		Box:             NewBox(),
    42  		field:           f,
    43  		cursor:          "_",
    44  		borderSize:      Scale(Style.InputBorderSize),
    45  		borderFocused:   Style.InputBorderFocused,
    46  		borderUnfocused: Style.InputBorderUnfocused,
    47  	}
    48  	i.SetBackground(Style.InputBgColor)
    49  	return i
    50  }
    51  
    52  // SetRect sets the position and size of the widget.
    53  func (i *Input) SetRect(r image.Rectangle) {
    54  	i.Box.rect = r
    55  
    56  	i.field.SetRect(r)
    57  
    58  	for _, w := range i.children {
    59  		w.SetRect(r)
    60  	}
    61  }
    62  
    63  // SetBorderSize sets the size of the border around the field.
    64  func (i *Input) SetBorderSize(size int) {
    65  	i.Lock()
    66  	defer i.Unlock()
    67  
    68  	i.borderSize = size
    69  }
    70  
    71  // SetBorderColors sets the border colors of the field when focused and unfocused.
    72  func (i *Input) SetBorderColors(focused color.RGBA, unfocused color.RGBA) {
    73  	i.Lock()
    74  	defer i.Unlock()
    75  
    76  	i.borderFocused = focused
    77  	i.borderUnfocused = unfocused
    78  }
    79  
    80  // Foreground return the color of the text within the field.
    81  func (i *Input) Foreground() color.RGBA {
    82  	i.Lock()
    83  	defer i.Unlock()
    84  
    85  	return i.field.ForegroundColor()
    86  }
    87  
    88  // SetForegroundColor sets the color of the text within the field.
    89  func (i *Input) SetForeground(c color.RGBA) {
    90  	i.Lock()
    91  	defer i.Unlock()
    92  
    93  	i.field.SetForegroundColor(c)
    94  }
    95  
    96  // SetPrefix sets the text shown before the input text.
    97  func (i *Input) SetPrefix(prefix string) {
    98  	i.Lock()
    99  	defer i.Unlock()
   100  
   101  	i.field.SetPrefix(prefix)
   102  }
   103  
   104  // SetSuffix sets the text shown after the input text.
   105  func (i *Input) SetSuffix(suffix string) {
   106  	i.Lock()
   107  	defer i.Unlock()
   108  
   109  	i.field.SetSuffix(suffix)
   110  }
   111  
   112  // SetCursor sets the cursor appended to the text buffer when focused.
   113  func (i *Input) SetCursor(cursor string) {
   114  	i.Lock()
   115  	defer i.Unlock()
   116  
   117  	i.cursor = cursor
   118  	if i.focus {
   119  		i.field.SetSuffix(cursor)
   120  	}
   121  }
   122  
   123  // Focus returns the focus state of the widget.
   124  func (i *Input) Focus() bool {
   125  	return i.focus
   126  }
   127  
   128  // SetFocus sets the focus state of the widget.
   129  func (i *Input) SetFocus(focus bool) bool {
   130  	i.focus = focus
   131  
   132  	var cursor string
   133  	if focus {
   134  		cursor = i.cursor
   135  	}
   136  	i.field.SetSuffix(cursor)
   137  	return true
   138  }
   139  
   140  // Text returns the content of the text buffer.
   141  func (i *Input) Text() string {
   142  	i.Lock()
   143  	defer i.Unlock()
   144  
   145  	return i.field.Text()
   146  }
   147  
   148  // SetText sets the text in the field.
   149  func (i *Input) SetText(text string) {
   150  	i.Lock()
   151  	defer i.Unlock()
   152  
   153  	i.field.SetText(text)
   154  }
   155  
   156  // SetScrollBarWidth sets the width of the scroll bar.
   157  func (i *Input) SetScrollBarWidth(width int) {
   158  	i.Lock()
   159  	defer i.Unlock()
   160  
   161  	i.field.SetScrollBarWidth(width)
   162  }
   163  
   164  // SetScrollBarColors sets the color of the scroll bar area and handle.
   165  func (i *Input) SetScrollBarColors(area color.RGBA, handle color.RGBA) {
   166  	i.Lock()
   167  	defer i.Unlock()
   168  
   169  	i.field.SetScrollBarColors(Style.ScrollAreaColor, Style.ScrollHandleColor)
   170  }
   171  
   172  // SetScrollBarVisible sets whether the scroll bar is visible on the screen.
   173  func (i *Input) SetScrollBarVisible(scrollVisible bool) {
   174  	i.Lock()
   175  	defer i.Unlock()
   176  
   177  	i.field.SetScrollBarVisible(scrollVisible)
   178  }
   179  
   180  // SetAutoHideScrollBar sets whether the scroll bar is automatically hidden
   181  // when the entire text buffer is visible.
   182  func (i *Input) SetAutoHideScrollBar(autoHide bool) {
   183  	i.Lock()
   184  	defer i.Unlock()
   185  
   186  	i.field.SetAutoHideScrollBar(autoHide)
   187  }
   188  
   189  // SetFont sets the font and text size of the field. Scaling is not applied.
   190  func (t *Input) SetFont(fnt *text.GoTextFaceSource, size int) {
   191  	t.Lock()
   192  	defer t.Unlock()
   193  
   194  	t.field.SetFont(fnt, size, fontMutex)
   195  }
   196  
   197  // SetAutoResize sets whether the font is automatically scaled down when it is
   198  // too large to fit the entire text buffer on one line.
   199  func (t *Input) SetAutoResize(resize bool) {
   200  	t.Lock()
   201  	defer t.Unlock()
   202  
   203  	t.field.SetAutoResize(resize)
   204  }
   205  
   206  // Padding returns the amount of padding around the text within the field.
   207  func (i *Input) Padding() int {
   208  	i.Lock()
   209  	defer i.Unlock()
   210  
   211  	return i.field.Padding()
   212  }
   213  
   214  // SetPadding sets the amount of padding around the text within the field.
   215  func (i *Input) SetPadding(padding int) {
   216  	i.Lock()
   217  	defer i.Unlock()
   218  
   219  	i.field.SetPadding(padding)
   220  }
   221  
   222  // SetWordWrap sets a flag which, when enabled, causes text to wrap without breaking words.
   223  func (i *Input) SetWordWrap(wrap bool) {
   224  	i.Lock()
   225  	defer i.Unlock()
   226  
   227  	i.field.SetWordWrap(wrap)
   228  }
   229  
   230  // SetHorizontal sets the horizontal alignment of the text within the field.
   231  func (i *Input) SetHorizontal(h Alignment) {
   232  	i.Lock()
   233  	defer i.Unlock()
   234  
   235  	i.field.SetHorizontal(messeji.Alignment(h))
   236  }
   237  
   238  // SetVertical sets the vertical alignment of the text within the field.
   239  func (i *Input) SetVertical(v Alignment) {
   240  	i.Lock()
   241  	defer i.Unlock()
   242  
   243  	i.field.SetVertical(messeji.Alignment(v))
   244  }
   245  
   246  // SetMask sets the rune used to mask the text buffer contents. Set to 0 to disable.
   247  func (i *Input) SetMask(r rune) {
   248  	i.Lock()
   249  	defer i.Unlock()
   250  
   251  	i.field.SetMask(r)
   252  }
   253  
   254  // Cursor returns the cursor shape shown when a mouse cursor hovers over the
   255  // widget, or -1 to let widgets beneath determine the cursor shape.
   256  func (i *Input) Cursor() ebiten.CursorShapeType {
   257  	return ebiten.CursorShapeText
   258  }
   259  
   260  // Write writes to the text buffer.
   261  func (i *Input) Write(p []byte) (n int, err error) {
   262  	return i.field.Write(p)
   263  }
   264  
   265  // HandleKeyboard is called when a keyboard event occurs.
   266  func (i *Input) HandleKeyboard(key ebiten.Key, r rune) (handled bool, err error) {
   267  	if !i.focus {
   268  		return false, nil
   269  	}
   270  
   271  	return i.field.HandleKeyboardEvent(key, r)
   272  }
   273  
   274  // HandleMouse is called when a mouse event occurs.
   275  func (i *Input) HandleMouse(cursor image.Point, pressed bool, clicked bool) (handled bool, err error) {
   276  	return i.field.HandleMouseEvent(cursor, pressed, clicked)
   277  }
   278  
   279  // Draw draws the widget on the screen.
   280  func (i *Input) Draw(screen *ebiten.Image) error {
   281  	i.field.Draw(screen)
   282  
   283  	// Draw border.
   284  	if i.borderSize == 0 {
   285  		return nil
   286  	}
   287  	r := i.rect
   288  	c := i.borderUnfocused
   289  	if i.focus {
   290  		c = i.borderFocused
   291  	}
   292  	screen.SubImage(image.Rect(r.Min.X, r.Min.Y, r.Min.X+i.borderSize, r.Max.Y)).(*ebiten.Image).Fill(c)
   293  	screen.SubImage(image.Rect(r.Min.X, r.Min.Y, r.Max.X, r.Min.Y+i.borderSize)).(*ebiten.Image).Fill(c)
   294  	screen.SubImage(image.Rect(r.Max.X-i.borderSize, r.Min.Y, r.Max.X, r.Max.Y)).(*ebiten.Image).Fill(c)
   295  	screen.SubImage(image.Rect(r.Min.X, r.Max.Y-i.borderSize, r.Max.X, r.Max.Y)).(*ebiten.Image).Fill(c)
   296  	return nil
   297  }
   298  

View as plain text