diff options
| author | Florian Fischer <florian.fischer@muhq.space> | 2023-02-03 14:05:14 +0100 |
|---|---|---|
| committer | Florian Fischer <florian.fischer@muhq.space> | 2025-08-20 15:46:38 +0200 |
| commit | 8802f30ff720fcb64d9207c4cb673dc6805390c2 (patch) | |
| tree | 9be529221105fc8681e3afb0e673e229ef9504d4 | |
| parent | e8f44219976edf8cf57cbd9e964f66fe9d145a9c (diff) | |
| download | muhqs-game-8802f30ff720fcb64d9207c4cb673dc6805390c2.tar.gz muhqs-game-8802f30ff720fcb64d9207c4cb673dc6805390c2.zip | |
add text input and properly center text
| -rw-r--r-- | go/client/startMenu.go | 71 | ||||
| -rw-r--r-- | go/ui/buffer.go | 13 | ||||
| -rw-r--r-- | go/ui/button.go | 11 | ||||
| -rw-r--r-- | go/ui/stateBar.go | 4 | ||||
| -rw-r--r-- | go/ui/textBox.go | 67 | ||||
| -rw-r--r-- | go/ui/textInput.go | 1 | ||||
| -rw-r--r-- | go/ui/utils.go | 19 |
7 files changed, 149 insertions, 37 deletions
diff --git a/go/client/startMenu.go b/go/client/startMenu.go index 735753b0..9d5d6129 100644 --- a/go/client/startMenu.go +++ b/go/client/startMenu.go @@ -1,6 +1,7 @@ package main import ( + "image/color" "log" "github.com/hajimehoshi/ebiten/v2" @@ -32,13 +33,38 @@ func NewStartMenu(app *app) *StartMenu { } func (m *StartMenu) build() { + playerLabel := ui.NewCenteringFixedTextBox( + (m.width-START_BUTTON_WIDTH)/2-START_BUTTON_WIDTH, + (m.height-START_BUTTON_HEIGHT)/2-START_BUTTON_HEIGHT, + START_BUTTON_WIDTH, + START_BUTTON_HEIGHT, + "name:", + ) + playerLabel.Bg = color.Black + m.widgets = append(m.widgets, playerLabel) + + playerInputLabel := "player name" + if m.playerName != "" { + playerInputLabel = m.playerName + } + + playerInput := ui.NewTextInput( + (m.width-START_BUTTON_WIDTH)/2, + (m.height-START_BUTTON_HEIGHT)/2-START_BUTTON_HEIGHT, + START_BUTTON_WIDTH, + START_BUTTON_HEIGHT, + playerInputLabel, + ) + m.widgets = append(m.widgets, playerInput) + m.widgets = append(m.widgets, ui.NewSimpleButton( (m.width-START_BUTTON_WIDTH)/2, (m.height-START_BUTTON_HEIGHT)/2, - 150, - 50, + START_BUTTON_WIDTH, + START_BUTTON_HEIGHT, "Start", func(*ui.SimpleButton) { + m.playerName = playerInput.Text() m.app.active = m.next() })) } @@ -49,15 +75,40 @@ func (m *StartMenu) Update() error { } x, y := ebiten.CursorPosition() + + var activeWidget ui.Widget + for _, w := range m.widgets { + if !w.Contains(x, y) { + continue + } + activeWidget = w + break + } + + if activeWidget == nil { + return nil + } + + scrollX, scrollY := ebiten.Wheel() + if scrollX != 0 || scrollY != 0 { + if scrollable, ok := activeWidget.(ui.Scrollable); ok { + scrollable.Scroll(int(scrollX), int(scrollY)) + } + } + + if textInput, ok := activeWidget.(*ui.TextInput); ok { + // var input []rune + // ebiten.AppendInputChars(input) + input := ebiten.InputChars() + if len(input) > 0 { + textInput.AddInput(input) + } + textInput.HandleKey() + } + if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) { - for _, w := range m.widgets { - if !w.Contains(x, y) { - continue - } - - if btn, ok := w.(ui.Button); ok { - btn.Click(x, y) - } + if btn, ok := activeWidget.(ui.Button); ok { + btn.Click(x, y) } } diff --git a/go/ui/buffer.go b/go/ui/buffer.go index c451d7fc..e95102fe 100644 --- a/go/ui/buffer.go +++ b/go/ui/buffer.go @@ -64,3 +64,16 @@ func (b *Buffer) Remove(idx int) { b.lines = append(b.lines[:idx], b.lines[idx+1:]...) b.ForceRedraw() } + +func (b *Buffer) Scroll(x, y int) { + if y == 0 { + return + } + + if y < 0 && b.pos > 0 { + b.pos-- + } else if y > 0 && b.pos < len(b.lines)-1 { + b.pos++ + } + b.ForceRedraw() +} diff --git a/go/ui/button.go b/go/ui/button.go index 6454ccac..0fd26936 100644 --- a/go/ui/button.go +++ b/go/ui/button.go @@ -35,15 +35,8 @@ func (b *SimpleButton) render() *ebiten.Image { ebitenutil.DrawRect(img, float64(0), float64(0), float64(b.Width), float64(b.Height), b.BG) bounds := text.BoundString(font.Font24, b.label) - x := (b.Width - bounds.Dx()) / 2 - if x < 0 { - x = 0 - } - - y := b.Height - bounds.Dy()/2 - if y < 0 { - y = 0 - } + x := b.Width/2 - centerTextXOffset(bounds) + y := b.Height/2 - centerTextYOffset(bounds) text.Draw(img, b.label, font.Font24, x, y, b.FG) return img } diff --git a/go/ui/stateBar.go b/go/ui/stateBar.go index 6914de6e..3b9407b5 100644 --- a/go/ui/stateBar.go +++ b/go/ui/stateBar.go @@ -50,12 +50,12 @@ func (sb *StateBar) FindObjectAt(x, y int) interface{} { func (sb *StateBar) ForceRedraw() { if sb.resourceView != nil { - sb.resourceView.Text = sb.resourceLabel() + sb.resourceView.text = sb.resourceLabel() sb.resourceView.ForceRedraw() } if sb.phaseView != nil { - sb.phaseView.Text = sb.phaseLabel() + sb.phaseView.text = sb.phaseLabel() sb.phaseView.ForceRedraw() } } diff --git a/go/ui/textBox.go b/go/ui/textBox.go index b4a580bf..d0afbd9b 100644 --- a/go/ui/textBox.go +++ b/go/ui/textBox.go @@ -5,6 +5,7 @@ import ( "image/color" "github.com/hajimehoshi/ebiten/v2" + "github.com/hajimehoshi/ebiten/v2/inpututil" "github.com/hajimehoshi/ebiten/v2/text" "muhq.space/muhqs-game/go/font" "muhq.space/muhqs-game/go/game" @@ -19,7 +20,7 @@ var ( type TextBox struct { WidgetBase - Text string + text string Fg color.Color Bg color.Color XMargin int @@ -30,7 +31,7 @@ type TextBox struct { func NewFixedTextBox(x, y int, width, height int, t string, center bool) *TextBox { tb := &TextBox{ WidgetBase: NewWidgetBase(x, y, width, height), - Text: t, + text: t, Fg: TEXTBOX_DEFAULT_FOREGROUND, Bg: TEXTBOX_DEFAULT_BACKGROUND, XMargin: TEXTBOX_DEFAULT_MARGIN, @@ -75,7 +76,7 @@ func NewPermInfo(x, y int, p game.Permanent) *TextBox { func (tb *TextBox) render() *ebiten.Image { var x, y int - b := text.BoundString(font.Font24, tb.Text) + b := text.BoundString(font.Font24, tb.text) if tb.Width == -1 || tb.Height == -1 { tb.Width = b.Dx() + 2*tb.XMargin tb.Height = b.Dy() + 2*tb.YMargin @@ -85,21 +86,15 @@ func (tb *TextBox) render() *ebiten.Image { if !tb.Center { x = tb.XMargin + b.Min.X } else { - x = (tb.Width - b.Dx()) / 2 - if x < 0 { - x = 0 - } + x = tb.Width/2 - centerTextXOffset(b) } - y = tb.Height - b.Dy()/2 - if y < 0 { - y = 0 - } + y = tb.Height/2 - centerTextYOffset(b) } img := ebiten.NewImage(tb.Width, tb.Height) img.Fill(tb.Bg) - text.Draw(img, tb.Text, font.Font24, x, y, tb.Fg) + text.Draw(img, tb.text, font.Font24, x, y, tb.Fg) return img } @@ -114,7 +109,7 @@ func NewPocList(centerX, bottomY int, poc game.PileOfCards) *PocList { w := &PocList{ TextBox: TextBox{ WidgetBase: NewWidgetBase(-1, -1, -1, -1), - Text: "", + text: "", Fg: TEXTBOX_DEFAULT_FOREGROUND, Bg: TEXTBOX_DEFAULT_BACKGROUND, XMargin: TEXTBOX_DEFAULT_MARGIN, @@ -139,12 +134,12 @@ func (w *PocList) setText() { } if t != "" { - w.Text = t[:len(t)-1] + w.text = t[:len(t)-1] } else { - w.Text = "No cards" + w.text = "No cards" } - b := text.BoundString(font.Font24, w.Text) + b := text.BoundString(font.Font24, w.text) w.X = w.centerX - b.Dx()/2 - w.XMargin w.Y = w.bottomY - b.Dy() - w.YMargin } @@ -159,3 +154,43 @@ func (w *PocList) FindObjectAt(x, y int) interface{} { // i := b.Dy() / w.poc.Size() return cards[0] } + +type TextInput struct { + TextBox + input string + label string +} + +func NewTextInput(x, y int, width, height int, label string) *TextInput { + w := &TextInput{*NewCenteringFixedTextBox(x, y, width, height, ""), "", label} + + w.renderImpl = func() *ebiten.Image { + if w.input == "" { + w.text = w.label + } else { + w.text = w.input + } + + return w.render() + } + + return w +} + +func (ti *TextInput) AddInput(input []rune) { + ti.input += string(input) + ti.ForceRedraw() +} + +func (ti *TextInput) HandleKey() { + if inpututil.IsKeyJustPressed(ebiten.KeyBackspace) { + if len(ti.input) > 0 { + ti.input = ti.input[:len(ti.input)-1] + ti.ForceRedraw() + } + } +} + +func (ti *TextInput) Text() string { + return ti.input +} diff --git a/go/ui/textInput.go b/go/ui/textInput.go new file mode 100644 index 00000000..5b1faa29 --- /dev/null +++ b/go/ui/textInput.go @@ -0,0 +1 @@ +package ui diff --git a/go/ui/utils.go b/go/ui/utils.go new file mode 100644 index 00000000..fd15b642 --- /dev/null +++ b/go/ui/utils.go @@ -0,0 +1,19 @@ +package ui + +import ( + "image" +) + +func centerTextXOffset(b image.Rectangle) int { + return (b.Dx() / 2) - b.Min.X +} + +func centerTextYOffset(b image.Rectangle) int { + return (b.Dy() / 2) + b.Min.Y +} + +func centerText(b image.Rectangle) (x int, y int) { + x = centerTextXOffset(b) + y = centerTextYOffset(b) + return +} |
