mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2024-09-28 22:26:30 -04:00
01927d0f3b
this also adds missing methods to elements not implementing widget. Note here that we do not enable sprite and label, as this would produce a crazy amount of linter warnings due to render() requiering error handling then, which non of the callers handle. Since we remove the render calls later anyways, we can postpone this static check for now.
218 lines
4.1 KiB
Go
218 lines
4.1 KiB
Go
package d2ui
|
|
|
|
import (
|
|
"log"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
|
)
|
|
|
|
// static check that TextBox implements widget
|
|
var _ Widget = &TextBox{}
|
|
|
|
// TextBox represents a text input box
|
|
type TextBox struct {
|
|
*BaseWidget
|
|
textLabel *Label
|
|
lineBar *Label
|
|
text string
|
|
filter string
|
|
bgSprite *Sprite
|
|
enabled bool
|
|
isFocused bool
|
|
}
|
|
|
|
// NewTextbox creates a new instance of a text box
|
|
func (ui *UIManager) NewTextbox() *TextBox {
|
|
bgSprite, err := ui.NewSprite(d2resource.TextBox2, d2resource.PaletteUnits)
|
|
if err != nil {
|
|
log.Print(err)
|
|
return nil
|
|
}
|
|
|
|
base := NewBaseWidget(ui)
|
|
|
|
tb := &TextBox{
|
|
BaseWidget: base,
|
|
filter: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
|
bgSprite: bgSprite,
|
|
textLabel: ui.NewLabel(d2resource.FontFormal11, d2resource.PaletteUnits),
|
|
lineBar: ui.NewLabel(d2resource.FontFormal11, d2resource.PaletteUnits),
|
|
enabled: true,
|
|
}
|
|
tb.lineBar.SetText("_")
|
|
|
|
ui.addWidget(tb)
|
|
|
|
return tb
|
|
}
|
|
|
|
// SetFilter sets the text box filter
|
|
func (v *TextBox) SetFilter(filter string) {
|
|
v.filter = filter
|
|
}
|
|
|
|
// Render renders the text box
|
|
func (v *TextBox) Render(target d2interface.Surface) error {
|
|
if !v.visible {
|
|
return nil
|
|
}
|
|
|
|
v.bgSprite.Render(target)
|
|
v.textLabel.Render(target)
|
|
|
|
if (time.Now().UnixNano()/1e6)&(1<<8) > 0 {
|
|
v.lineBar.Render(target)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// OnKeyChars handles key character events
|
|
func (v *TextBox) OnKeyChars(event d2interface.KeyCharsEvent) bool {
|
|
if !v.isFocused || !v.visible || !v.enabled {
|
|
return false
|
|
}
|
|
|
|
newText := string(event.Chars())
|
|
|
|
if len(newText) > 0 {
|
|
v.text += newText
|
|
|
|
v.SetText(v.text)
|
|
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// OnKeyRepeat handles key repeat events
|
|
func (v *TextBox) OnKeyRepeat(event d2interface.KeyEvent) bool {
|
|
if event.Key() == d2enum.KeyBackspace && debounceEvents(event.Duration()) {
|
|
if len(v.text) >= 1 {
|
|
v.text = v.text[:len(v.text)-1]
|
|
}
|
|
|
|
v.SetText(v.text)
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func debounceEvents(numFrames int) bool {
|
|
const (
|
|
delay = 30
|
|
interval = 3
|
|
)
|
|
|
|
if numFrames == 1 {
|
|
return true
|
|
}
|
|
|
|
if numFrames >= delay && (numFrames-delay)%interval == 0 {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// Advance updates the text box
|
|
func (v *TextBox) Advance(_ float64) error {
|
|
return nil
|
|
}
|
|
|
|
// Update updates the textbox (not currently implemented)
|
|
func (v *TextBox) Update() {
|
|
}
|
|
|
|
// GetText returns the text box's text
|
|
func (v *TextBox) GetText() string {
|
|
return v.text
|
|
}
|
|
|
|
// SetText sets the text box's text
|
|
//nolint:gomnd // Built-in values
|
|
func (v *TextBox) SetText(newText string) {
|
|
result := ""
|
|
|
|
for _, c := range newText {
|
|
if !strings.Contains(v.filter, string(c)) {
|
|
continue
|
|
}
|
|
|
|
result += string(c)
|
|
}
|
|
|
|
if len(result) > 15 {
|
|
result = result[0:15]
|
|
}
|
|
|
|
v.text = result
|
|
|
|
for {
|
|
tw, _ := v.textLabel.GetTextMetrics(result)
|
|
|
|
if tw > 150 {
|
|
result = result[1:]
|
|
continue
|
|
}
|
|
|
|
v.lineBar.SetPosition(v.x+6+tw, v.y+3)
|
|
v.textLabel.SetText(result)
|
|
|
|
break
|
|
}
|
|
}
|
|
|
|
// GetSize returns the size of the text box
|
|
func (v *TextBox) GetSize() (width, height int) {
|
|
return v.bgSprite.GetCurrentFrameSize()
|
|
}
|
|
|
|
// SetPosition sets the position of the text box
|
|
//nolint:gomnd // Built-in values
|
|
func (v *TextBox) SetPosition(x, y int) {
|
|
lw, _ := v.textLabel.GetSize()
|
|
|
|
v.x = x
|
|
v.y = y
|
|
|
|
v.textLabel.SetPosition(v.x+6, v.y+3)
|
|
v.lineBar.SetPosition(v.x+6+lw, v.y+3)
|
|
v.bgSprite.SetPosition(v.x, v.y+26)
|
|
}
|
|
|
|
// GetEnabled returns the enabled state of the text box
|
|
func (v *TextBox) GetEnabled() bool {
|
|
return v.enabled
|
|
}
|
|
|
|
// SetEnabled sets the enabled state of the text box
|
|
func (v *TextBox) SetEnabled(enabled bool) {
|
|
v.enabled = enabled
|
|
}
|
|
|
|
// SetPressed does nothing for text boxes
|
|
func (v *TextBox) SetPressed(_ bool) {
|
|
// no op
|
|
}
|
|
|
|
// GetPressed does nothing for text boxes
|
|
func (v *TextBox) GetPressed() bool {
|
|
return false
|
|
}
|
|
|
|
// OnActivated handles activation events for the text box
|
|
func (v *TextBox) OnActivated(_ func()) {
|
|
// no op
|
|
}
|
|
|
|
// Activate activates the text box
|
|
func (v *TextBox) Activate() {
|
|
v.isFocused = true
|
|
}
|