From f1564757315b7cfb517d7e382ff6b3a95a740632 Mon Sep 17 00:00:00 2001 From: Tim Sarbin Date: Sun, 10 Nov 2019 12:28:41 -0500 Subject: [PATCH] Added text entry. Fixed performance issue. Added error checking. (#132) --- d2core/d2scene/CharacterSelect.go | 20 ++-- d2core/d2scene/Credits.go | 10 +- d2core/d2scene/MainMenu.go | 34 +++---- d2core/d2scene/SelectHeroClass.go | 69 +++++++++---- d2render/AnimatedEntity.go | 5 +- d2render/Sprite.go | 18 ++-- d2render/d2ui/Button.go | 20 ++-- d2render/d2ui/Label.go | 11 ++- d2render/d2ui/TextBox.go | 158 ++++++++++++++++++++++++++++++ 9 files changed, 275 insertions(+), 70 deletions(-) create mode 100644 d2render/d2ui/TextBox.go diff --git a/d2core/d2scene/CharacterSelect.go b/d2core/d2scene/CharacterSelect.go index abd691ea..dc3c7cae 100644 --- a/d2core/d2scene/CharacterSelect.go +++ b/d2core/d2scene/CharacterSelect.go @@ -19,11 +19,11 @@ type CharacterSelect struct { fileProvider d2interface.FileProvider sceneProvider d2interface.SceneProvider background d2render.Sprite - newCharButton *d2ui.Button - convertCharButton *d2ui.Button - deleteCharButton *d2ui.Button - exitButton *d2ui.Button - okButton *d2ui.Button + newCharButton d2ui.Button + convertCharButton d2ui.Button + deleteCharButton d2ui.Button + exitButton d2ui.Button + okButton d2ui.Button } func CreateCharacterSelect( @@ -52,31 +52,31 @@ func (v *CharacterSelect) Load() []func() { v.newCharButton = d2ui.CreateButton(d2ui.ButtonTypeTall, v.fileProvider, dh.CombineStrings(dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#831"), 15))) v.newCharButton.MoveTo(33, 468) v.newCharButton.OnActivated(func() { v.onNewCharButtonClicked() }) - v.uiManager.AddWidget(v.newCharButton) + v.uiManager.AddWidget(&v.newCharButton) }, func() { v.convertCharButton = d2ui.CreateButton(d2ui.ButtonTypeTall, v.fileProvider, dh.CombineStrings(dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#825"), 15))) v.convertCharButton.MoveTo(233, 468) v.convertCharButton.SetEnabled(false) - v.uiManager.AddWidget(v.convertCharButton) + v.uiManager.AddWidget(&v.convertCharButton) }, func() { v.deleteCharButton = d2ui.CreateButton(d2ui.ButtonTypeTall, v.fileProvider, dh.CombineStrings(dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#832"), 15))) v.deleteCharButton.MoveTo(433, 468) v.deleteCharButton.SetEnabled(false) - v.uiManager.AddWidget(v.deleteCharButton) + v.uiManager.AddWidget(&v.deleteCharButton) }, func() { v.exitButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, v.fileProvider, d2common.TranslateString("#970")) v.exitButton.MoveTo(33, 537) v.exitButton.OnActivated(func() { v.onExitButtonClicked() }) - v.uiManager.AddWidget(v.exitButton) + v.uiManager.AddWidget(&v.exitButton) }, func() { v.okButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, v.fileProvider, d2common.TranslateString("#971")) v.okButton.MoveTo(625, 537) v.okButton.SetEnabled(false) - v.uiManager.AddWidget(v.okButton) + v.uiManager.AddWidget(&v.okButton) }, } } diff --git a/d2core/d2scene/Credits.go b/d2core/d2scene/Credits.go index 9ecdea92..3e81cbf4 100644 --- a/d2core/d2scene/Credits.go +++ b/d2core/d2scene/Credits.go @@ -22,7 +22,7 @@ import ( ) type labelItem struct { - Label *d2ui.Label + Label d2ui.Label IsHeading bool Available bool } @@ -34,7 +34,7 @@ type Credits struct { fileProvider d2interface.FileProvider sceneProvider d2interface.SceneProvider creditsBackground d2render.Sprite - exitButton *d2ui.Button + exitButton d2ui.Button creditsText []string labels []*labelItem cycleTime float64 @@ -68,7 +68,7 @@ func (v *Credits) Load() []func() { v.exitButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, v.fileProvider, d2common.TranslateString("#970")) v.exitButton.MoveTo(30, 550) v.exitButton.OnActivated(func() { v.onExitButtonClicked() }) - v.uiManager.AddWidget(v.exitButton) + v.uiManager.AddWidget(&v.exitButton) }, func() { fileData, _ := dh.Utf16BytesToString(v.fileProvider.LoadFile(d2resource.CreditsText)[2:]) @@ -192,7 +192,7 @@ func (v *Credits) getNewFontLabel(isHeading bool) *d2ui.Label { } else { label.Label.Color = color.RGBA{198, 178, 150, 255} } - return label.Label + return &label.Label } } @@ -210,5 +210,5 @@ func (v *Credits) getNewFontLabel(isHeading bool) *d2ui.Label { } v.labels = append(v.labels, newLabelItem) - return newLabelItem.Label + return &newLabelItem.Label } diff --git a/d2core/d2scene/MainMenu.go b/d2core/d2scene/MainMenu.go index 5289a283..4b098dfd 100644 --- a/d2core/d2scene/MainMenu.go +++ b/d2core/d2scene/MainMenu.go @@ -37,17 +37,17 @@ type MainMenu struct { diabloLogoRight d2render.Sprite diabloLogoLeftBack d2render.Sprite diabloLogoRightBack d2render.Sprite - singlePlayerButton *d2ui.Button - githubButton *d2ui.Button - exitDiabloButton *d2ui.Button - creditsButton *d2ui.Button - cinematicsButton *d2ui.Button - mapTestButton *d2ui.Button - copyrightLabel *d2ui.Label - copyrightLabel2 *d2ui.Label - openDiabloLabel *d2ui.Label - versionLabel *d2ui.Label - commitLabel *d2ui.Label + singlePlayerButton d2ui.Button + githubButton d2ui.Button + exitDiabloButton d2ui.Button + creditsButton d2ui.Button + cinematicsButton d2ui.Button + mapTestButton d2ui.Button + copyrightLabel d2ui.Label + copyrightLabel2 d2ui.Label + openDiabloLabel d2ui.Label + versionLabel d2ui.Label + commitLabel d2ui.Label ShowTrademarkScreen bool leftButtonHeld bool @@ -138,41 +138,41 @@ func (v *MainMenu) Load() []func() { v.exitDiabloButton.MoveTo(264, 535) v.exitDiabloButton.SetVisible(!v.ShowTrademarkScreen) v.exitDiabloButton.OnActivated(func() { v.onExitButtonClicked() }) - v.uiManager.AddWidget(v.exitDiabloButton) + v.uiManager.AddWidget(&v.exitDiabloButton) }, func() { v.creditsButton = d2ui.CreateButton(d2ui.ButtonTypeShort, v.fileProvider, d2common.TranslateString("#1627")) v.creditsButton.MoveTo(264, 505) v.creditsButton.SetVisible(!v.ShowTrademarkScreen) v.creditsButton.OnActivated(func() { v.onCreditsButtonClicked() }) - v.uiManager.AddWidget(v.creditsButton) + v.uiManager.AddWidget(&v.creditsButton) }, func() { v.cinematicsButton = d2ui.CreateButton(d2ui.ButtonTypeShort, v.fileProvider, d2common.TranslateString("#1639")) v.cinematicsButton.MoveTo(401, 505) v.cinematicsButton.SetVisible(!v.ShowTrademarkScreen) - v.uiManager.AddWidget(v.cinematicsButton) + v.uiManager.AddWidget(&v.cinematicsButton) }, func() { v.singlePlayerButton = d2ui.CreateButton(d2ui.ButtonTypeWide, v.fileProvider, d2common.TranslateString("#1620")) v.singlePlayerButton.MoveTo(264, 290) v.singlePlayerButton.SetVisible(!v.ShowTrademarkScreen) v.singlePlayerButton.OnActivated(func() { v.onSinglePlayerClicked() }) - v.uiManager.AddWidget(v.singlePlayerButton) + v.uiManager.AddWidget(&v.singlePlayerButton) }, func() { v.githubButton = d2ui.CreateButton(d2ui.ButtonTypeWide, v.fileProvider, "PROJECT WEBSITE") v.githubButton.MoveTo(264, 330) v.githubButton.SetVisible(!v.ShowTrademarkScreen) v.githubButton.OnActivated(func() { v.onGithubButtonClicked() }) - v.uiManager.AddWidget(v.githubButton) + v.uiManager.AddWidget(&v.githubButton) }, func() { v.mapTestButton = d2ui.CreateButton(d2ui.ButtonTypeWide, v.fileProvider, "MAP ENGINE TEST") v.mapTestButton.MoveTo(264, 450) v.mapTestButton.SetVisible(!v.ShowTrademarkScreen) v.mapTestButton.OnActivated(func() { v.onMapTestClicked() }) - v.uiManager.AddWidget(v.mapTestButton) + v.uiManager.AddWidget(&v.mapTestButton) }, } } diff --git a/d2core/d2scene/SelectHeroClass.go b/d2core/d2scene/SelectHeroClass.go index 2a2ef7ea..5163aff0 100644 --- a/d2core/d2scene/SelectHeroClass.go +++ b/d2core/d2scene/SelectHeroClass.go @@ -2,6 +2,7 @@ package d2scene import ( "image" + "image/color" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource" @@ -35,20 +36,23 @@ type HeroRenderInfo struct { } type SelectHeroClass struct { - uiManager *d2ui.Manager - soundManager *d2audio.Manager - fileProvider d2interface.FileProvider - sceneProvider d2interface.SceneProvider - bgImage d2render.Sprite - campfire d2render.Sprite - headingLabel *d2ui.Label - heroClassLabel *d2ui.Label - heroDesc1Label *d2ui.Label - heroDesc2Label *d2ui.Label - heroDesc3Label *d2ui.Label - heroRenderInfo map[d2enum.Hero]*HeroRenderInfo - selectedHero d2enum.Hero - exitButton *d2ui.Button + uiManager *d2ui.Manager + soundManager *d2audio.Manager + fileProvider d2interface.FileProvider + sceneProvider d2interface.SceneProvider + bgImage d2render.Sprite + campfire d2render.Sprite + headingLabel d2ui.Label + heroClassLabel d2ui.Label + heroDesc1Label d2ui.Label + heroDesc2Label d2ui.Label + heroDesc3Label d2ui.Label + heroNameTextbox d2ui.TextBox + heroNameLabel d2ui.Label + heroRenderInfo map[d2enum.Hero]*HeroRenderInfo + selectedHero d2enum.Hero + exitButton d2ui.Button + okButton d2ui.Button } func CreateSelectHeroClass( @@ -115,7 +119,28 @@ func (v *SelectHeroClass) Load() []func() { v.exitButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, v.fileProvider, d2common.TranslateString("#970")) v.exitButton.MoveTo(33, 537) v.exitButton.OnActivated(func() { v.onExitButtonClicked() }) - v.uiManager.AddWidget(v.exitButton) + v.uiManager.AddWidget(&v.exitButton) + }, + func() { + v.okButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, v.fileProvider, d2common.TranslateString("#971")) + v.okButton.MoveTo(630, 537) + v.okButton.OnActivated(func() { v.onOkButtonClicked() }) + v.okButton.SetVisible(false) + v.okButton.SetEnabled(false) + v.uiManager.AddWidget(&v.okButton) + }, + func() { + v.heroNameLabel = d2ui.CreateLabel(v.fileProvider, d2resource.Font16, d2enum.Units) + v.heroNameLabel.Alignment = d2ui.LabelAlignLeft + v.heroNameLabel.Color = color.RGBA{216, 196, 128, 255} + v.heroNameLabel.SetText(d2common.TranslateString("#1694")) + v.heroNameLabel.MoveTo(321, 475) + }, + func() { + v.heroNameTextbox = d2ui.CreateTextbox(v.fileProvider) + v.heroNameTextbox.MoveTo(318, 493) + v.heroNameTextbox.SetVisible(false) + v.uiManager.AddWidget(&v.heroNameTextbox) }, func() { v.heroRenderInfo[d2enum.HeroBarbarian] = &HeroRenderInfo{ @@ -368,10 +393,14 @@ func (v *SelectHeroClass) Unload() { v.heroRenderInfo = nil } -func (v *SelectHeroClass) onExitButtonClicked() { +func (v SelectHeroClass) onExitButtonClicked() { v.sceneProvider.SetNextScene(CreateCharacterSelect(v.fileProvider, v.sceneProvider, v.uiManager, v.soundManager)) } +func (v SelectHeroClass) onOkButtonClicked() { + // TODO: Start the game +} + func (v *SelectHeroClass) Render(screen *ebiten.Image) { v.bgImage.DrawSegments(screen, 4, 3, 0) v.headingLabel.Draw(screen) @@ -392,6 +421,9 @@ func (v *SelectHeroClass) Render(screen *ebiten.Image) { } } v.campfire.Draw(screen) + if v.heroNameTextbox.GetVisible() { + v.heroNameLabel.Draw(screen) + } } func (v *SelectHeroClass) Update(tickTime float64) { @@ -412,6 +444,8 @@ func (v *SelectHeroClass) Update(tickTime float64) { if v.selectedHero != d2enum.HeroNone && allIdle { v.selectedHero = d2enum.HeroNone } + v.heroNameTextbox.Update() + v.okButton.SetEnabled(len(v.heroNameTextbox.GetText()) >= 2) } func (v *SelectHeroClass) updateHeroSelectionHover(hero d2enum.Hero, canSelect bool) { @@ -444,7 +478,8 @@ func (v *SelectHeroClass) updateHeroSelectionHover(hero d2enum.Hero, canSelect b b := renderInfo.SelectionBounds mouseHover := (mouseX >= b.Min.X) && (mouseX <= b.Min.X+b.Max.X) && (mouseY >= b.Min.Y) && (mouseY <= b.Min.Y+b.Max.Y) if mouseHover && v.uiManager.CursorButtonPressed(d2ui.CursorButtonLeft) { - // showEntryUi = true; + v.heroNameTextbox.SetVisible(true) + v.okButton.SetVisible(true) renderInfo.Stance = d2enum.HeroStanceApproaching renderInfo.ForwardWalkSprite.ResetAnimation() if renderInfo.ForwardWalkSpriteOverlay.IsValid() { diff --git a/d2render/AnimatedEntity.go b/d2render/AnimatedEntity.go index cdda4109..194e83e5 100644 --- a/d2render/AnimatedEntity.go +++ b/d2render/AnimatedEntity.go @@ -3,6 +3,7 @@ package d2render import ( "fmt" "image" + "log" "strings" "time" @@ -156,7 +157,9 @@ func (v *AnimatedEntity) Render(target *ebiten.Image, offsetX, offsetY int) { opts := &ebiten.DrawImageOptions{} opts.GeoM.Translate(float64(v.frameLocations[frameName][v.currentFrame].Left+offsetX), float64(v.frameLocations[frameName][v.currentFrame].Top+offsetY+40)) - target.DrawImage(v.frames[frameName][v.currentFrame], opts) + if err := target.DrawImage(v.frames[frameName][v.currentFrame], opts); err != nil { + log.Panic(err.Error()) + } } } diff --git a/d2render/Sprite.go b/d2render/Sprite.go index b2161d26..4f66287c 100644 --- a/d2render/Sprite.go +++ b/d2render/Sprite.go @@ -4,6 +4,7 @@ import ( "encoding/binary" "image" "image/color" + "log" "sync" "time" @@ -29,7 +30,6 @@ type Sprite struct { LastFrameTime time.Time Animate bool ColorMod color.Color - visible bool valid bool } @@ -104,7 +104,7 @@ func CreateSprite(data []byte, palette d2datadict.PaletteRec) Sprite { x := uint32(0) y := result.Frames[i].Height - 1 - for true { + for { b := data[dataPointer] dataPointer++ if b == 0x80 { @@ -197,7 +197,9 @@ func (v *Sprite) cacheFrame(frame int) { v.atlasBytes[idx+3] = v.Frames[frame].FrameData[pix+3] } } - v.atlas.ReplacePixels(v.atlasBytes) + if err := v.atlas.ReplacePixels(v.atlasBytes); err != nil { + log.Panic(err.Error()) + } v.Frames[frame].cached = true } @@ -218,7 +220,7 @@ func (v *Sprite) updateAnimation() { } else { timePerFrame = time.Duration(float64(time.Second) * (1.0 / float64(len(v.Frames)))) } - for time.Now().Sub(v.LastFrameTime) >= timePerFrame { + for time.Since(v.LastFrameTime) >= timePerFrame { v.LastFrameTime = v.LastFrameTime.Add(timePerFrame) v.Frame++ if v.Frame >= uint8(v.FramesPerDirection) { @@ -272,7 +274,9 @@ func (v *Sprite) Draw(target *ebiten.Image) { if v.ColorMod != nil { opts.ColorM = d2helper.ColorToColorM(v.ColorMod) } - target.DrawImage(frame.Image, opts) + if err := target.DrawImage(frame.Image, opts); err != nil { + log.Panic(err.Error()) + } } // DrawSegments draws the sprite via a grid of segments @@ -300,7 +304,9 @@ func (v *Sprite) DrawSegments(target *ebiten.Image, xSegments, ySegments, offset if v.ColorMod != nil { opts.ColorM = d2helper.ColorToColorM(v.ColorMod) } - target.DrawImage(frame.Image, opts) + if err := target.DrawImage(frame.Image, opts); err != nil { + log.Panic(err.Error()) + } xOffset += int32(frame.Width) biggestYOffset = d2helper.MaxInt32(biggestYOffset, int32(frame.Height)) } diff --git a/d2render/d2ui/Button.go b/d2render/d2ui/Button.go index 3f3b54f2..b19a0ac5 100644 --- a/d2render/d2ui/Button.go +++ b/d2render/d2ui/Button.go @@ -108,8 +108,8 @@ type Button struct { } // CreateButton creates an instance of Button -func CreateButton(buttonType ButtonType, fileProvider d2interface.FileProvider, text string) *Button { - result := &Button{ +func CreateButton(buttonType ButtonType, fileProvider d2interface.FileProvider, text string) Button { + result := Button{ fileProvider: fileProvider, width: 0, height: 0, @@ -159,7 +159,7 @@ func CreateButton(buttonType ButtonType, fileProvider d2interface.FileProvider, if buttonLayout.DisabledFrame != -1 { result.disabledImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest) buttonSprite.DrawSegments(result.disabledImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.DisabledFrame) - font.Draw(0, textY-1, text, color.RGBA{100, 100, 100, 255}, result.disabledImage) + font.Draw(0, textY, text, color.RGBA{100, 100, 100, 255}, result.disabledImage) } } return result @@ -171,7 +171,7 @@ func (v *Button) OnActivated(callback func()) { } // Activate calls the on activated callback handler, if any -func (v *Button) Activate() { +func (v Button) Activate() { if v.onClick == nil { return } @@ -179,7 +179,7 @@ func (v *Button) Activate() { } // Draw renders the button -func (v *Button) Draw(target *ebiten.Image) { +func (v Button) Draw(target *ebiten.Image) { opts := &ebiten.DrawImageOptions{ CompositeMode: ebiten.CompositeModeSourceAtop, Filter: ebiten.FilterNearest, @@ -202,7 +202,7 @@ func (v *Button) Draw(target *ebiten.Image) { } // GetEnabled returns the enabled state -func (v *Button) GetEnabled() bool { +func (v Button) GetEnabled() bool { return v.enabled } @@ -212,7 +212,7 @@ func (v *Button) SetEnabled(enabled bool) { } // GetSize returns the size of the button -func (v *Button) GetSize() (uint32, uint32) { +func (v Button) GetSize() (uint32, uint32) { return v.width, v.height } @@ -223,12 +223,12 @@ func (v *Button) MoveTo(x, y int) { } // GetLocation returns the location of the button -func (v *Button) GetLocation() (x, y int) { +func (v Button) GetLocation() (x, y int) { return v.x, v.y } // GetVisible returns the visibility of the button -func (v *Button) GetVisible() bool { +func (v Button) GetVisible() bool { return v.visible } @@ -238,7 +238,7 @@ func (v *Button) SetVisible(visible bool) { } // GetPressed returns the pressed state of the button -func (v *Button) GetPressed() bool { +func (v Button) GetPressed() bool { return v.pressed } diff --git a/d2render/d2ui/Label.go b/d2render/d2ui/Label.go index e0706bc0..80ee93cc 100644 --- a/d2render/d2ui/Label.go +++ b/d2render/d2ui/Label.go @@ -36,13 +36,12 @@ type Label struct { } // CreateLabel creates a new instance of a UI label -func CreateLabel(provider d2interface.FileProvider, font string, palette d2enum.PaletteType) *Label { - result := &Label{ +func CreateLabel(provider d2interface.FileProvider, font string, palette d2enum.PaletteType) Label { + result := Label{ Alignment: LabelAlignLeft, Color: color.White, font: GetFont(font, palette, provider), } - return result } @@ -72,6 +71,10 @@ func (v *Label) MoveTo(x, y int) { v.Y = y } +func (v *Label) GetTextMetrics(text string) (width, height uint32) { + return v.font.GetTextMetrics(text) +} + func (v *Label) cacheImage() { if v.imageData != nil { return @@ -93,7 +96,7 @@ func (v *Label) SetText(newText string) { } // GetSize returns the size of the label -func (v *Label) GetSize() (width, height uint32) { +func (v Label) GetSize() (width, height uint32) { v.cacheImage() width = v.Width height = v.Height diff --git a/d2render/d2ui/TextBox.go b/d2render/d2ui/TextBox.go new file mode 100644 index 00000000..7494a839 --- /dev/null +++ b/d2render/d2ui/TextBox.go @@ -0,0 +1,158 @@ +package d2ui + +import ( + "strings" + "time" + + "github.com/hajimehoshi/ebiten/inpututil" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource" + "github.com/OpenDiablo2/OpenDiablo2/d2data/d2datadict" + "github.com/OpenDiablo2/OpenDiablo2/d2render" + "github.com/hajimehoshi/ebiten" +) + +// TextBox represents a text input box +type TextBox struct { + text string + x int + y int + visible bool + enabled bool + bgSprite d2render.Sprite + textLabel Label + lineBar Label +} + +func CreateTextbox(fileProvider d2interface.FileProvider) TextBox { + result := TextBox{ + bgSprite: d2render.CreateSprite(fileProvider.LoadFile(d2resource.TextBox2), d2datadict.Palettes[d2enum.Units]), + textLabel: CreateLabel(fileProvider, d2resource.FontFormal11, d2enum.Units), + lineBar: CreateLabel(fileProvider, d2resource.FontFormal11, d2enum.Units), + enabled: true, + visible: true, + } + result.lineBar.SetText("_") + return result +} + +func repeatingKeyPressed(key ebiten.Key) bool { + const ( + delay = 30 + interval = 3 + ) + d := inpututil.KeyPressDuration(key) + if d == 1 { + return true + } + if d >= delay && (d-delay)%interval == 0 { + return true + } + return false +} + +func (v TextBox) Draw(target *ebiten.Image) { + if !v.visible { + return + } + v.bgSprite.Draw(target) + v.textLabel.Draw(target) + if (time.Now().UnixNano()/1e6)&(1<<8) > 0 { + v.lineBar.Draw(target) + } +} + +func (v *TextBox) Update() { + if !v.visible || !v.enabled { + return + } + newText := string(ebiten.InputChars()) + if len(newText) > 0 { + v.text += newText + v.SetText(v.text) + } + if repeatingKeyPressed(ebiten.KeyBackspace) { + if len(v.text) >= 1 { + v.text = v.text[:len(v.text)-1] + } + v.SetText(v.text) + } +} + +func (v TextBox) GetText() string { + return v.text +} + +func (v *TextBox) SetText(newText string) { + result := "" + for _, c := range newText { + if !strings.Contains("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 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.MoveTo(v.x+6+int(tw), v.y+3) + v.textLabel.SetText(result) + break + } +} + +func (v TextBox) GetSize() (width, height uint32) { + return v.bgSprite.GetSize() +} + +func (v *TextBox) MoveTo(x, y int) { + v.x = x + v.y = y + v.textLabel.MoveTo(v.x+6, v.y+3) + v.lineBar.MoveTo(v.x+6+int(v.textLabel.Width), v.y+3) + v.bgSprite.MoveTo(v.x, v.y+26) +} + +func (v TextBox) GetLocation() (x, y int) { + return v.x, v.y +} + +func (v TextBox) GetVisible() bool { + return v.visible +} + +func (v *TextBox) SetVisible(visible bool) { + v.visible = visible +} + +func (v TextBox) GetEnabled() bool { + return v.enabled +} + +func (v *TextBox) SetEnabled(enabled bool) { + v.enabled = enabled +} + +func (v *TextBox) SetPressed(pressed bool) { + // no op +} + +func (v TextBox) GetPressed() bool { + return false +} + +func (v *TextBox) OnActivated(callback func()) { + // no op +} + +func (v TextBox) Activate() { + //no op +}