diff --git a/box.go b/box.go index ed85892..ad3e6f0 100644 --- a/box.go +++ b/box.go @@ -22,7 +22,8 @@ type Box struct { // NewBox returns a new Box widget. func NewBox() *Box { return &Box{ - visible: true, + background: transparent, + visible: true, } } diff --git a/button.go b/button.go index a67cddc..dc46f20 100644 --- a/button.go +++ b/button.go @@ -3,17 +3,18 @@ package etk import ( "image" "image/color" + "sync" "code.rocket9labs.com/tslocum/etk/messeji" "github.com/hajimehoshi/ebiten/v2" + "golang.org/x/image/font" ) // Button is a clickable button. type Button struct { *Box - - Label *messeji.TextField - + field *messeji.TextField + borderSize int borderTop color.RGBA borderRight color.RGBA borderBottom color.RGBA @@ -27,19 +28,18 @@ func NewButton(label string, onSelected func() error) *Button { if textColor.A == 0 { textColor = Style.TextColorDark } - - l := messeji.NewTextField(Style.TextFont, Style.TextFontMutex) - l.SetText(label) - l.SetForegroundColor(textColor) - l.SetBackgroundColor(transparent) - l.SetHorizontal(messeji.AlignCenter) - l.SetVertical(messeji.AlignCenter) - l.SetScrollBarVisible(false) + f := newText() + f.SetText(label) + f.SetForegroundColor(textColor) + f.SetHorizontal(messeji.AlignCenter) + f.SetVertical(messeji.AlignCenter) + f.SetScrollBarVisible(false) return &Button{ Box: NewBox(), - Label: l, + field: f, onSelected: onSelected, + borderSize: Scale(Style.BorderSize), borderTop: Style.BorderColorTop, borderRight: Style.BorderColorRight, borderBottom: Style.BorderColorBottom, @@ -51,7 +51,7 @@ func NewButton(label string, onSelected func() error) *Button { func (b *Button) SetRect(r image.Rectangle) { b.Box.rect = r - b.Label.SetRect(r) + b.field.SetRect(r) for _, w := range b.children { w.SetRect(r) @@ -69,6 +69,30 @@ func (b *Button) SetBorderColor(top color.RGBA, right color.RGBA, bottom color.R b.borderLeft = left } +// Text returns the content of the text buffer. +func (b *Button) Text() string { + b.Lock() + defer b.Unlock() + + return b.field.Text() +} + +// SetText sets the text in the field. +func (b *Button) SetText(text string) { + b.Lock() + defer b.Unlock() + + b.field.SetText(text) +} + +// SetFont sets the font face of the text within the field. +func (b *Button) SetFont(face font.Face, mutex *sync.Mutex) { + b.Lock() + defer b.Unlock() + + b.field.SetFont(face, mutex) +} + // HandleKeyboard is called when a keyboard event occurs. func (b *Button) HandleKeyboard(ebiten.Key, rune) (handled bool, err error) { return false, nil @@ -99,7 +123,7 @@ func (b *Button) Draw(screen *ebiten.Image) error { screen.SubImage(r).(*ebiten.Image).Fill(Style.ButtonBgColor) // Draw label. - b.Label.Draw(screen) + b.field.Draw(screen) // Draw border. const borderSize = 4 diff --git a/examples/grid/main.go b/examples/grid/main.go index 1961328..675aa03 100644 --- a/examples/grid/main.go +++ b/examples/grid/main.go @@ -7,7 +7,6 @@ import ( "log" "code.rocket9labs.com/tslocum/etk" - "code.rocket9labs.com/tslocum/etk/messeji" "github.com/hajimehoshi/ebiten/v2" ) @@ -23,8 +22,8 @@ func main() { newText := func(size int) *etk.Text { t := etk.NewText(fmt.Sprintf("%dpx Text", size)) - t.SetHorizontal(messeji.AlignCenter) - t.SetVertical(messeji.AlignCenter) + t.SetHorizontal(etk.AlignCenter) + t.SetVertical(etk.AlignCenter) return t } diff --git a/examples/showcase/main.go b/examples/showcase/main.go index 45577ff..be3de65 100644 --- a/examples/showcase/main.go +++ b/examples/showcase/main.go @@ -39,7 +39,8 @@ func main() { buffer.Write([]byte("\nInput: " + text)) return true } - input := etk.NewInput(">", "", onselected) + input := etk.NewInput("", onselected) + input.SetPrefix(">") { inputDemo := etk.NewFlex() inputDemo.SetVertical(true) diff --git a/game.go b/game.go index e91641c..3b7cf6d 100644 --- a/game.go +++ b/game.go @@ -9,12 +9,27 @@ import ( "strings" "time" + "code.rocket9labs.com/tslocum/etk/messeji" "github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2/inpututil" "golang.org/x/image/font" "golang.org/x/image/math/fixed" ) +// Alignment specifies how text is aligned within the field. +type Alignment int + +const ( + // AlignStart aligns text at the start of the field. + AlignStart Alignment = 0 + + // AlignCenter aligns text at the center of the field. + AlignCenter Alignment = 1 + + // AlignEnd aligns text at the end of the field. + AlignEnd Alignment = 2 +) + var root Widget var drawDebug bool @@ -386,6 +401,16 @@ func draw(w Widget, screen *ebiten.Image) error { return nil } +func newText() *messeji.TextField { + f := messeji.NewTextField(Style.TextFont, Style.TextFontMutex) + f.SetForegroundColor(Style.TextColorLight) + f.SetBackgroundColor(transparent) + f.SetScrollBarColors(Style.ScrollAreaColor, Style.ScrollHandleColor) + f.SetScrollBorderSize(Scale(Style.ScrollBorderSize)) + f.SetScrollBorderColors(Style.ScrollBorderColorTop, Style.ScrollBorderColorRight, Style.ScrollBorderColorBottom, Style.ScrollBorderColorLeft) + return f +} + func rectAtOrigin(r image.Rectangle) image.Rectangle { r.Max.X, r.Max.Y = r.Dx(), r.Dy() r.Min.X, r.Min.Y = 0, 0 diff --git a/input.go b/input.go index 6323349..67e678b 100644 --- a/input.go +++ b/input.go @@ -2,56 +2,107 @@ package etk import ( "image" + "image/color" + "sync" "code.rocket9labs.com/tslocum/etk/messeji" "github.com/hajimehoshi/ebiten/v2" + "golang.org/x/image/font" ) // Input is a text input widget. The Input widget is simply a Text widget that // also accepts user input. type Input struct { *Box - Field *messeji.InputField - Cursor string + field *messeji.InputField + cursor string focus bool } // NewInput returns a new Input widget. -func NewInput(prefix string, text string, onSelected func(text string) (handled bool)) *Input { +func NewInput(text string, onSelected func(text string) (handled bool)) *Input { textColor := Style.TextColorDark /*if TextColor == nil { textColor = Style.InputColor }*/ - i := messeji.NewInputField(Style.TextFont, Style.TextFontMutex) - i.SetPrefix(prefix) - i.SetSuffix("") - i.SetText(text) - i.SetForegroundColor(textColor) - i.SetBackgroundColor(Style.InputBgColor) - i.SetHandleKeyboard(true) - i.SetSelectedFunc(func() (accept bool) { - return onSelected(i.Text()) + f := messeji.NewInputField(Style.TextFont, Style.TextFontMutex) + f.SetForegroundColor(textColor) + f.SetBackgroundColor(transparent) + f.SetScrollBarColors(Style.ScrollAreaColor, Style.ScrollHandleColor) + f.SetScrollBorderSize(Scale(Style.ScrollBorderSize)) + f.SetScrollBorderColors(Style.ScrollBorderColorTop, Style.ScrollBorderColorRight, Style.ScrollBorderColorBottom, Style.ScrollBorderColorLeft) + f.SetPrefix("") + f.SetSuffix("") + f.SetText(text) + f.SetHandleKeyboard(true) + f.SetSelectedFunc(func() (accept bool) { + return onSelected(f.Text()) }) - return &Input{ + i := &Input{ Box: NewBox(), - Field: i, - Cursor: "_", + field: f, + cursor: "_", } + i.SetBackground(Style.InputBgColor) + return i } // SetRect sets the position and size of the widget. func (i *Input) SetRect(r image.Rectangle) { i.Box.rect = r - i.Field.SetRect(r) + i.field.SetRect(r) for _, w := range i.children { w.SetRect(r) } } +// Foreground return the color of the text within the field. +func (i *Input) Foreground() color.RGBA { + i.Lock() + defer i.Unlock() + + return i.field.ForegroundColor() +} + +// SetForegroundColor sets the color of the text within the field. +func (i *Input) SetForeground(c color.RGBA) { + i.Lock() + defer i.Unlock() + + i.field.SetForegroundColor(c) +} + +// SetPrefix sets the text shown before the input text. +func (i *Input) SetPrefix(prefix string) { + i.Lock() + defer i.Unlock() + + i.field.SetPrefix(prefix) +} + +// SetSuffix sets the text shown after the input text. +func (i *Input) SetSuffix(suffix string) { + i.Lock() + defer i.Unlock() + + i.field.SetSuffix(suffix) +} + +// SetCursor sets the cursor appended to the text buffer when focused. +func (i *Input) SetCursor(cursor string) { + i.Lock() + defer i.Unlock() + + i.cursor = cursor + if i.focus { + i.field.SetSuffix(cursor) + } +} + // Focus returns the focus state of the widget. func (i *Input) Focus() bool { return i.focus @@ -63,25 +114,112 @@ func (i *Input) SetFocus(focus bool) bool { var cursor string if focus { - cursor = i.Cursor + cursor = i.cursor } - i.Field.SetSuffix(cursor) + i.field.SetSuffix(cursor) return true } -// Clear clears the textbuffer. -func (i *Input) Clear() { - i.Field.SetText("") -} - -// Write writes to the text buffer. -func (i *Input) Write(p []byte) (n int, err error) { - return i.Field.Write(p) -} - // Text returns the content of the text buffer. func (i *Input) Text() string { - return i.Field.Text() + i.Lock() + defer i.Unlock() + + return i.field.Text() +} + +// SetText sets the text in the field. +func (i *Input) SetText(text string) { + i.Lock() + defer i.Unlock() + + i.field.SetText(text) +} + +// SetScrollBarWidth sets the width of the scroll bar. +func (i *Input) SetScrollBarWidth(width int) { + i.Lock() + defer i.Unlock() + + i.field.SetScrollBarWidth(width) +} + +// SetScrollBarColors sets the color of the scroll bar area and handle. +func (i *Input) SetScrollBarColors(area color.RGBA, handle color.RGBA) { + i.Lock() + defer i.Unlock() + + i.field.SetScrollBarColors(Style.ScrollAreaColor, Style.ScrollHandleColor) +} + +// SetScrollBarVisible sets whether the scroll bar is visible on the screen. +func (i *Input) SetScrollBarVisible(scrollVisible bool) { + i.Lock() + defer i.Unlock() + + i.field.SetScrollBarVisible(scrollVisible) +} + +// SetAutoHideScrollBar sets whether the scroll bar is automatically hidden +// when the entire text buffer is visible. +func (i *Input) SetAutoHideScrollBar(autoHide bool) { + i.Lock() + defer i.Unlock() + + i.field.SetAutoHideScrollBar(autoHide) +} + +// SetFont sets the font face of the text within the field. +func (i *Input) SetFont(face font.Face, mutex *sync.Mutex) { + i.Lock() + defer i.Unlock() + + i.field.SetFont(face, mutex) +} + +// Padding returns the amount of padding around the text within the field. +func (i *Input) Padding() int { + i.Lock() + defer i.Unlock() + + return i.field.Padding() +} + +// SetPadding sets the amount of padding around the text within the field. +func (i *Input) SetPadding(padding int) { + i.Lock() + defer i.Unlock() + + i.field.SetPadding(padding) +} + +// SetWordWrap sets a flag which, when enabled, causes text to wrap without breaking words. +func (i *Input) SetWordWrap(wrap bool) { + i.Lock() + defer i.Unlock() + + i.field.SetWordWrap(wrap) +} + +// SetHorizontal sets the horizontal alignment of the text within the field. +func (i *Input) SetHorizontal(h Alignment) { + i.Lock() + defer i.Unlock() + + i.field.SetHorizontal(messeji.Alignment(h)) +} + +// SetVertical sets the vertical alignment of the text within the field. +func (i *Input) SetVertical(h Alignment) { + i.Lock() + defer i.Unlock() + + i.field.SetVertical(messeji.Alignment(h)) +} + +// Write writes to the text buffer. +func (i *Input) Write(p []byte) (n int, err error) { + return i.field.Write(p) } // HandleKeyboard is called when a keyboard event occurs. @@ -90,16 +228,16 @@ func (i *Input) HandleKeyboard(key ebiten.Key, r rune) (handled bool, err error) return false, nil } - return i.Field.HandleKeyboardEvent(key, r) + return i.field.HandleKeyboardEvent(key, r) } // HandleMouse is called when a mouse event occurs. func (i *Input) HandleMouse(cursor image.Point, pressed bool, clicked bool) (handled bool, err error) { - return i.Field.HandleMouseEvent(cursor, pressed, clicked) + return i.field.HandleMouseEvent(cursor, pressed, clicked) } // Draw draws the widget on the screen. func (i *Input) Draw(screen *ebiten.Image) error { - i.Field.Draw(screen) + i.field.Draw(screen) return nil } diff --git a/kibodo/keyboard.go b/kibodo/keyboard.go index d1ab7e5..b85654b 100644 --- a/kibodo/keyboard.go +++ b/kibodo/keyboard.go @@ -39,8 +39,8 @@ type Keyboard struct { op *ebiten.DrawImageOptions - backgroundColor color.Color - lastBackgroundColor color.Color + backgroundColor color.RGBA + lastBackgroundColor color.RGBA shift bool @@ -78,7 +78,7 @@ func NewKeyboard() *Keyboard { normalKeys: KeysQWERTY, backgroundLower: ebiten.NewImage(1, 1), backgroundUpper: ebiten.NewImage(1, 1), - backgroundColor: color.Black, + backgroundColor: color.RGBA{0, 0, 0, 255}, holdTouchID: -1, labelFont: fontFace, backspaceDelay: 500 * time.Millisecond, diff --git a/messeji/textfield.go b/messeji/textfield.go index 62ef809..e4cb24d 100644 --- a/messeji/textfield.go +++ b/messeji/textfield.go @@ -113,10 +113,10 @@ type TextField struct { lineOffset int // textColor is the color of the text within the field. - textColor color.Color + textColor color.RGBA // backgroundColor is the color of the background of the field. - backgroundColor color.Color + backgroundColor color.RGBA // padding is the amount of padding around the text within the field. padding int @@ -150,6 +150,15 @@ type TextField struct { // scrollHandleColor is the color of the scroll handle. scrollHandleColor color.RGBA + // scrollBorderSize is the size of the border around the scroll bar handle. + scrollBorderSize int + + // Scroll bar handle border colors. + scrollBorderTop color.RGBA + scrollBorderRight color.RGBA + scrollBorderBottom color.RGBA + scrollBorderLeft color.RGBA + // scrollVisible is whether the scroll bar is visible on the screen. scrollVisible bool @@ -272,7 +281,7 @@ func (f *TextField) SetPrefix(text string) { f.modified = true } -// SetSuffix sets the text shown before the content of the field. +// SetSuffix sets the text shown after the content of the field. func (f *TextField) SetSuffix(text string) { f.Lock() defer f.Unlock() @@ -361,8 +370,16 @@ func (f *TextField) SetLineHeight(height int) { f.modified = true } +// ForegroundColor returns the color of the text within the field. +func (f *TextField) ForegroundColor() color.RGBA { + f.Lock() + defer f.Unlock() + + return f.textColor +} + // SetForegroundColor sets the color of the text within the field. -func (f *TextField) SetForegroundColor(c color.Color) { +func (f *TextField) SetForegroundColor(c color.RGBA) { f.Lock() defer f.Unlock() @@ -371,7 +388,7 @@ func (f *TextField) SetForegroundColor(c color.Color) { } // SetBackgroundColor sets the color of the background of the field. -func (f *TextField) SetBackgroundColor(c color.Color) { +func (f *TextField) SetBackgroundColor(c color.RGBA) { f.Lock() defer f.Unlock() @@ -463,6 +480,28 @@ func (f *TextField) SetScrollBarColors(area color.RGBA, handle color.RGBA) { f.redraw = true } +// SetScrollBorderSize sets the size of the border around the scroll bar handle. +func (f *TextField) SetScrollBorderSize(size int) { + f.Lock() + defer f.Unlock() + + f.scrollBorderSize = size + f.redraw = true +} + +// SetScrollBorderColor sets the color of the top, right, bottom and left border +// of the scroll bar handle. +func (f *TextField) SetScrollBorderColors(top color.RGBA, right color.RGBA, bottom color.RGBA, left color.RGBA) { + f.Lock() + defer f.Unlock() + + f.scrollBorderTop = top + f.scrollBorderRight = right + f.scrollBorderBottom = bottom + f.scrollBorderLeft = left + f.redraw = true +} + // SetScrollBarVisible sets whether the scroll bar is visible on the screen. func (f *TextField) SetScrollBarVisible(scrollVisible bool) { f.Lock() @@ -870,7 +909,11 @@ func (f *TextField) wrapContent(withScrollBar bool) { // drawContent draws the text buffer to img. func (f *TextField) drawContent() (overflow bool) { - f.img.Fill(f.backgroundColor) + if f.backgroundColor.A != 0 { + f.img.Fill(f.backgroundColor) + } else { + f.img.Clear() + } fieldWidth := f.r.Dx() fieldHeight := f.r.Dy() if f.showScrollBar() { @@ -1017,8 +1060,20 @@ func (f *TextField) drawImage() { scrollY += int(float64(h-scrollBarH) * pct) scrollBarRect := image.Rect(scrollX, scrollY, scrollX+f.scrollWidth, scrollY+scrollBarH) + // Draw scroll area. f.img.SubImage(f.scrollRect).(*ebiten.Image).Fill(f.scrollAreaColor) + + // Draw scroll handle. f.img.SubImage(scrollBarRect).(*ebiten.Image).Fill(f.scrollHandleColor) + + // Draw scroll handle border. + if f.scrollBorderSize != 0 { + r := scrollBarRect + f.img.SubImage(image.Rect(r.Min.X, r.Min.Y, r.Min.X+f.scrollBorderSize, r.Max.Y)).(*ebiten.Image).Fill(f.scrollBorderLeft) + f.img.SubImage(image.Rect(r.Min.X, r.Min.Y, r.Max.X, r.Min.Y+f.scrollBorderSize)).(*ebiten.Image).Fill(f.scrollBorderTop) + f.img.SubImage(image.Rect(r.Max.X-f.scrollBorderSize, r.Min.Y, r.Max.X, r.Max.Y)).(*ebiten.Image).Fill(f.scrollBorderRight) + f.img.SubImage(image.Rect(r.Min.X, r.Max.Y-f.scrollBorderSize, r.Max.X, r.Max.Y)).(*ebiten.Image).Fill(f.scrollBorderBottom) + } } } diff --git a/select.go b/select.go index a04f148..e3fa106 100644 --- a/select.go +++ b/select.go @@ -4,14 +4,12 @@ import ( "image" "image/color" - "code.rocket9labs.com/tslocum/etk/messeji" "github.com/hajimehoshi/ebiten/v2" ) // Select is a dropdown selection widget. type Select struct { *Box - label *Text list *List onSelect func(index int) (accept bool) @@ -26,9 +24,9 @@ func NewSelect(itemHeight int, onSelect func(index int) (accept bool)) *Select { label: NewText(""), onSelect: onSelect, } - s.label.SetVertical(messeji.AlignCenter) - s.label.SetForegroundColor(Style.ButtonTextColor) - s.label.SetBackgroundColor(Style.ButtonBgColor) + s.label.SetVertical(AlignCenter) + s.label.SetForeground(Style.ButtonTextColor) + s.SetBackground(Style.ButtonBgColor) s.list = NewList(itemHeight, s.selectList) s.list.SetBackground(Style.ButtonBgColor) s.list.SetDrawBorder(true) @@ -109,8 +107,8 @@ func (s *Select) AddOption(label string) { } t := NewText(label) - t.SetVertical(messeji.AlignCenter) - t.SetForegroundColor(Style.ButtonTextColor) + t.SetVertical(AlignCenter) + t.SetForeground(Style.ButtonTextColor) s.list.AddChildAt(t, 0, len(s.items)-1) } diff --git a/style.go b/style.go index e31046f..9c3e445 100644 --- a/style.go +++ b/style.go @@ -29,7 +29,7 @@ func defaultFont() font.Face { return defaultFont } -// Attributes represents a default attribute configuration. +// Attributes represents a default attribute configuration. Integer values will be scaled. type Attributes struct { TextFont font.Face TextFontMutex *sync.Mutex @@ -39,14 +39,23 @@ type Attributes struct { TextBgColor color.RGBA - ScrollAreaColor color.RGBA - ScrollHandleColor color.RGBA + BorderSize int BorderColorTop color.RGBA BorderColorRight color.RGBA BorderColorBottom color.RGBA BorderColorLeft color.RGBA + ScrollAreaColor color.RGBA + ScrollHandleColor color.RGBA + + ScrollBorderSize int + + ScrollBorderColorTop color.RGBA + ScrollBorderColorRight color.RGBA + ScrollBorderColorBottom color.RGBA + ScrollBorderColorLeft color.RGBA + InputBgColor color.RGBA ButtonTextColor color.RGBA @@ -54,7 +63,7 @@ type Attributes struct { ButtonBgColorDisabled color.RGBA } -// Style is the current default attribute configuration. +// Style is the current default attribute configuration. Integer values will be scaled. var Style = &Attributes{ TextFont: defaultFont(), TextFontMutex: &sync.Mutex{}, @@ -64,13 +73,22 @@ var Style = &Attributes{ TextBgColor: transparent, + BorderSize: 4, + + BorderColorTop: color.RGBA{220, 220, 220, 255}, + BorderColorRight: color.RGBA{0, 0, 0, 255}, + BorderColorBottom: color.RGBA{0, 0, 0, 255}, + BorderColorLeft: color.RGBA{220, 220, 220, 255}, + ScrollAreaColor: color.RGBA{200, 200, 200, 255}, ScrollHandleColor: color.RGBA{108, 108, 108, 255}, - BorderColorTop: color.RGBA{255, 255, 255, 255}, - BorderColorRight: color.RGBA{0, 0, 0, 255}, - BorderColorBottom: color.RGBA{0, 0, 0, 255}, - BorderColorLeft: color.RGBA{255, 255, 255, 255}, + ScrollBorderSize: 2, + + ScrollBorderColorTop: color.RGBA{240, 240, 240, 255}, + ScrollBorderColorRight: color.RGBA{0, 0, 0, 255}, + ScrollBorderColorBottom: color.RGBA{0, 0, 0, 255}, + ScrollBorderColorLeft: color.RGBA{240, 240, 240, 255}, InputBgColor: color.RGBA{0, 128, 0, 255}, diff --git a/text.go b/text.go index 0d3eabb..6e97327 100644 --- a/text.go +++ b/text.go @@ -3,49 +3,56 @@ package etk import ( "image" "image/color" + "sync" "code.rocket9labs.com/tslocum/etk/messeji" "github.com/hajimehoshi/ebiten/v2" + "golang.org/x/image/font" ) // Text is a text display widget. type Text struct { - *messeji.TextField - - background color.RGBA - children []Widget + *Box + field *messeji.TextField + children []Widget } // NewText returns a new Text widget. func NewText(text string) *Text { - textColor := Style.TextColorLight - - l := messeji.NewTextField(Style.TextFont, Style.TextFontMutex) - l.SetText(text) - l.SetForegroundColor(textColor) - l.SetBackgroundColor(Style.TextBgColor) - l.SetScrollBarColors(Style.ScrollAreaColor, Style.ScrollHandleColor) - l.SetHandleKeyboard(true) + f := newText() + f.SetText(text) + f.SetForegroundColor(Style.TextColorLight) + f.SetHandleKeyboard(true) return &Text{ - TextField: l, + Box: NewBox(), + field: f, } } -// Background returns the background color of the widget. -func (t *Text) Background() color.RGBA { +// SetRect sets the position and size of the widget. +func (t *Text) SetRect(r image.Rectangle) { t.Lock() defer t.Unlock() - return t.background + t.rect = r + t.field.SetRect(r) } -// SetBackground sets the background color of the widget. -func (t *Text) SetBackground(background color.RGBA) { +// Foreground return the color of the text within the field. +func (t *Text) Foreground() color.RGBA { t.Lock() defer t.Unlock() - t.background = background + return t.field.ForegroundColor() +} + +// SetForegroundColor sets the color of the text within the field. +func (t *Text) SetForeground(c color.RGBA) { + t.Lock() + defer t.Unlock() + + t.field.SetForegroundColor(c) } // Focus returns the focus state of the widget. @@ -58,34 +65,151 @@ func (t *Text) SetFocus(focus bool) bool { return false } -// Clear clears the text buffer. -func (t *Text) Clear() { - t.TextField.SetText("") +// SetScrollBarWidth sets the width of the scroll bar. +func (t *Text) SetScrollBarWidth(width int) { + t.Lock() + defer t.Unlock() + + t.field.SetScrollBarWidth(width) +} + +// SetScrollBarColors sets the color of the scroll bar area and handle. +func (t *Text) SetScrollBarColors(area color.RGBA, handle color.RGBA) { + t.Lock() + defer t.Unlock() + + t.field.SetScrollBarColors(Style.ScrollAreaColor, Style.ScrollHandleColor) +} + +// SetScrollBorderColor sets the color of the top, right, bottom and left border +// of the scroll bar handle. +func (t *Text) SetScrollBorderColors(top color.RGBA, right color.RGBA, bottom color.RGBA, left color.RGBA) { + t.Lock() + defer t.Unlock() + + t.field.SetScrollBorderColors(top, right, bottom, left) +} + +// SetWordWrap sets a flag which, when enabled, causes text to wrap without breaking words. +func (t *Text) SetWordWrap(wrap bool) { + t.Lock() + defer t.Unlock() + + t.field.SetWordWrap(wrap) +} + +// SetHorizontal sets the horizontal alignment of the text within the field. +func (t *Text) SetHorizontal(h Alignment) { + t.Lock() + defer t.Unlock() + + t.field.SetHorizontal(messeji.Alignment(h)) +} + +// SetVertical sets the vertical alignment of the text within the field. +func (t *Text) SetVertical(h Alignment) { + t.Lock() + defer t.Unlock() + + t.field.SetVertical(messeji.Alignment(h)) } // Write writes to the text buffer. func (t *Text) Write(p []byte) (n int, err error) { - return t.TextField.Write(p) + t.Lock() + defer t.Unlock() + + return t.field.Write(p) } // Text returns the content of the text buffer. func (t *Text) Text() string { - return t.TextField.Text() + t.Lock() + defer t.Unlock() + + return t.field.Text() +} + +// SetText sets the text in the field. +func (t *Text) SetText(text string) { + t.Lock() + defer t.Unlock() + + t.field.SetText(text) +} + +// SetScrollBarVisible sets whether the scroll bar is visible on the screen. +func (t *Text) SetScrollBarVisible(scrollVisible bool) { + t.Lock() + defer t.Unlock() + + t.field.SetScrollBarVisible(scrollVisible) +} + +// SetAutoHideScrollBar sets whether the scroll bar is automatically hidden +// when the entire text buffer is visible. +func (t *Text) SetAutoHideScrollBar(autoHide bool) { + t.Lock() + defer t.Unlock() + + t.field.SetAutoHideScrollBar(autoHide) +} + +// SetFont sets the font face of the text within the field. +func (t *Text) SetFont(face font.Face, mutex *sync.Mutex) { + t.Lock() + defer t.Unlock() + + t.field.SetFont(face, mutex) +} + +// Padding returns the amount of padding around the text within the field. +func (t *Text) Padding() int { + t.Lock() + defer t.Unlock() + + return t.field.Padding() +} + +// SetPadding sets the amount of padding around the text within the field. +func (t *Text) SetPadding(padding int) { + t.Lock() + defer t.Unlock() + + t.field.SetPadding(padding) +} + +// SetFollow sets whether the field should automatically scroll to the end when +// content is added to the buffer. +func (t *Text) SetFollow(follow bool) { + t.Lock() + defer t.Unlock() + + t.field.SetFollow(follow) +} + +// SetSingleLine sets whether the field displays all text on a single line. +// When enabled, the field scrolls horizontally. Otherwise, it scrolls vertically. +func (t *Text) SetSingleLine(single bool) { + t.Lock() + defer t.Unlock() + + t.field.SetSingleLine(single) } // HandleKeyboard is called when a keyboard event occurs. func (t *Text) HandleKeyboard(key ebiten.Key, r rune) (handled bool, err error) { - return t.TextField.HandleKeyboardEvent(key, r) + return t.field.HandleKeyboardEvent(key, r) } // HandleMouse is called when a mouse event occurs. func (t *Text) HandleMouse(cursor image.Point, pressed bool, clicked bool) (handled bool, err error) { - return t.TextField.HandleMouseEvent(cursor, pressed, clicked) + return t.field.HandleMouseEvent(cursor, pressed, clicked) } // Draw draws the widget on the screen. func (t *Text) Draw(screen *ebiten.Image) error { - t.TextField.Draw(screen) + t.field.Draw(screen) return nil }