Reposition chat interface when on-screen keyboard is shown

This commit is contained in:
Trevor Slocum 2023-11-08 14:50:05 -08:00
parent a07be68a70
commit 5bbf8e2711
6 changed files with 118 additions and 113 deletions

View file

@ -1,3 +1,6 @@
1.1.0:
- Reposition chat interface when on-screen keyboard is shown
1.0.9:
- Reposition buttons when viewing board
- Replace reset button with undo

View file

@ -90,11 +90,17 @@ type board struct {
uiGrid *etk.Grid
frame *etk.Frame
lastKeyboardToggle time.Time
bearOffOverlay *etk.Button
leaveGameGrid *etk.Grid
confirmLeaveGameFrame *etk.Frame
chatGrid *etk.Grid
floatInputGrid *etk.Grid
floatChatGrid *etk.Grid
fontFace font.Face
lineHeight int
lineOffset int
@ -140,6 +146,9 @@ func NewBoard() *board {
uiGrid: etk.NewGrid(),
frame: etk.NewFrame(),
confirmLeaveGameFrame: etk.NewFrame(),
chatGrid: etk.NewGrid(),
floatChatGrid: etk.NewGrid(),
floatInputGrid: etk.NewGrid(),
fontFace: mediumFont,
Mutex: &sync.Mutex{},
}
@ -219,7 +228,6 @@ func NewBoard() *board {
b.clockLabel = clockLabel
b.showMenuButton = etk.NewButton("Menu", b.showMenu)
b.showMenuButton.Label.SetFont(smallFont, fontMutex)
b.matchStatusGrid = etk.NewGrid()
b.matchStatusGrid.AddChildAt(b.timerLabel, 0, 0, 1, 1)
@ -250,6 +258,26 @@ func NewBoard() *board {
b.frame.AddChild(b.buttonsGrid)
{
b.chatGrid.SetBackground(tableColor)
b.chatGrid.AddChildAt(floatStatusBuffer, 0, 0, 1, 1)
b.chatGrid.AddChildAt(etk.NewBox(), 0, 1, 1, 1)
b.chatGrid.AddChildAt(b.floatInputGrid, 0, 2, 1, 1)
b.chatGrid.AddChildAt(etk.NewBox(), 0, 3, 1, 1)
padding := etk.NewBox()
padding.SetBackground(tableColor)
g := b.floatChatGrid
g.SetRowSizes(-1, -1, -1)
g.AddChildAt(b.chatGrid, 0, 1, 1, 1)
g.AddChildAt(padding, 0, 2, 1, 1)
g.SetVisible(false)
b.frame.AddChild(g)
}
b.frame.AddChild(b.floatChatGrid)
{
f := etk.NewFrame()
f.AddChild(b.menuGrid)
@ -286,9 +314,18 @@ func (b *board) fontUpdated() {
}
}
statusBuffer.SetFont(bufferFont, fontMutex)
floatStatusBuffer.SetFont(bufferFont, fontMutex)
gameBuffer.SetFont(bufferFont, fontMutex)
inputBuffer.Field.SetFont(bufferFont, fontMutex)
if game.TouchInput {
b.showMenuButton.Label.SetFont(largeFont, fontMutex)
} else {
b.showMenuButton.Label.SetFont(smallFont, fontMutex)
}
b.showKeyboardButton.Label.SetFont(largeFont, fontMutex)
b.timerLabel.SetFont(b.fontFace, fontMutex)
b.clockLabel.SetFont(b.fontFace, fontMutex)
}
@ -299,19 +336,25 @@ func (b *board) recreateInputGrid() {
} else {
*b.inputGrid = *etk.NewGrid()
}
*b.floatInputGrid = *etk.NewGrid()
if game.TouchInput {
b.inputGrid.AddChildAt(inputBuffer, 0, 0, 2, 1)
b.floatInputGrid.AddChildAt(inputBuffer, 0, 0, 2, 1)
b.inputGrid.AddChildAt(etk.NewBox(), 0, 1, 2, 1)
b.floatInputGrid.AddChildAt(etk.NewBox(), 0, 1, 2, 1)
showMenuButton := etk.NewButton(gotext.Get("Menu"), b.showMenu)
b.inputGrid.AddChildAt(showMenuButton, 0, 2, 1, 1)
b.inputGrid.AddChildAt(b.showMenuButton, 0, 2, 1, 1)
b.floatInputGrid.AddChildAt(b.showMenuButton, 0, 2, 1, 1)
b.inputGrid.AddChildAt(b.showKeyboardButton, 1, 2, 1, 1)
b.floatInputGrid.AddChildAt(b.showKeyboardButton, 1, 2, 1, 1)
b.inputGrid.SetRowSizes(52, int(b.horizontalBorderSize/2), -1)
b.floatInputGrid.SetRowSizes(52, int(b.horizontalBorderSize/2), -1)
} else {
b.inputGrid.AddChildAt(inputBuffer, 0, 0, 1, 1)
b.floatInputGrid.AddChildAt(inputBuffer, 0, 0, 1, 1)
}
}
@ -402,16 +445,6 @@ func (b *board) recreateButtonGrid() {
*b.buttonsUndoOKGrid = *buttonGrid(false, undoButton, okButton)
}
func (b *board) setKeyboardRect() {
inputAndButtons := 52
if game.TouchInput {
inputAndButtons = 52 + int(b.horizontalBorderSize) + game.scale(baseButtonHeight)
}
h := game.screenH / 3
y := game.screenH - game.screenH/3 - inputAndButtons - int(b.horizontalBorderSize)
game.keyboard.SetRect(0, y, game.screenW, h)
}
func (b *board) cancelLeaveGame() error {
b.leaveGameGrid.SetVisible(false)
return nil
@ -446,11 +479,20 @@ func (b *board) showMenu() error {
}
func (b *board) toggleKeyboard() error {
t := time.Now()
if !b.lastKeyboardToggle.IsZero() && t.Sub(b.lastKeyboardToggle) < 200*time.Millisecond {
return nil
}
b.lastKeyboardToggle = t
if game.keyboard.Visible() {
game.keyboard.Hide()
b.floatChatGrid.SetVisible(false)
b.uiGrid.SetRect(b.uiGrid.Rect())
b.showKeyboardButton.Label.SetText(gotext.Get("Show Keyboard"))
} else {
b.setKeyboardRect()
b.floatChatGrid.SetVisible(true)
b.floatChatGrid.SetRect(b.floatChatGrid.Rect())
game.keyboard.Show()
b.showKeyboardButton.Label.SetText(gotext.Get("Hide Keyboard"))
}
@ -660,39 +702,6 @@ func (b *board) updateBackgroundImage() {
}
}
func (b *board) drawButton(target *ebiten.Image, r image.Rectangle, label string) {
w, h := r.Dx(), r.Dy()
if w == 0 || h == 0 {
return
}
baseImg := image.NewRGBA(image.Rect(0, 0, w, h))
gc := draw2dimg.NewGraphicContext(baseImg)
gc.SetLineWidth(5)
gc.SetStrokeColor(color.Black)
gc.MoveTo(0, 0)
gc.LineTo(float64(w), 0)
gc.LineTo(float64(w), float64(h))
gc.LineTo(0, float64(h))
gc.Close()
gc.Stroke()
img := ebiten.NewImage(w, h)
img.Fill(color.RGBA{225.0, 188, 125, 255})
img.DrawImage(ebiten.NewImageFromImage(baseImg), nil)
fontMutex.Lock()
defer fontMutex.Unlock()
bounds := etk.BoundString(b.fontFace, label)
text.Draw(img, label, b.fontFace, (w-bounds.Dx())/2, (h+(bounds.Dy()/2))/2, color.Black)
op := &ebiten.DrawImageOptions{}
op.GeoM.Translate(float64(r.Min.X), float64(r.Min.Y))
target.DrawImage(img, op)
}
func (b *board) drawSprite(target *ebiten.Image, sprite *Sprite) {
x, y := float64(sprite.x), float64(sprite.y)
if !sprite.toStart.IsZero() {
@ -1054,9 +1063,7 @@ func (b *board) setRect(x, y, w, h int) {
b.menuGrid.SetColumnSizes(-1, game.scale(10), -1, game.scale(10), -1)
if viewBoard && game.keyboard.Visible() {
b.setKeyboardRect()
}
b.chatGrid.SetRowSizes(-1, int(b.horizontalBorderSize)/2, inputAndButtons, int(b.horizontalBorderSize)/2)
}
func (b *board) updateOpponentLabel() {

View file

@ -39,7 +39,7 @@ const version = "v1.0.9"
const MaxDebug = 1
const baseButtonHeight = 46
const baseButtonHeight = 56
var onlyNumbers = regexp.MustCompile(`[0-9]+`)
@ -63,7 +63,6 @@ var (
smallFont font.Face
mediumFont font.Face
largeFont font.Face
monoFont font.Face
gameFont font.Face
@ -86,24 +85,20 @@ const (
const (
smallFontSize = 20
monoFontSize = 10
mediumFontSize = 24
largeFontSize = 36
)
const (
monoLineHeight = 14
)
var (
bufferTextColor = triangleALight
bufferBackgroundColor = color.RGBA{40, 24, 9, 255}
)
var (
statusBuffer = etk.NewText("")
gameBuffer = etk.NewText("")
inputBuffer = etk.NewInput("", "", acceptInput)
statusBuffer = etk.NewText("")
floatStatusBuffer = etk.NewText("")
gameBuffer = etk.NewText("")
inputBuffer = etk.NewInput("", "", acceptInput)
statusLogged bool
gameLogged bool
@ -145,10 +140,12 @@ func l(s string) {
m := time.Now().Format("15:04") + " " + s
if statusLogged {
_, _ = statusBuffer.Write([]byte("\n" + m))
_, _ = floatStatusBuffer.Write([]byte("\n" + m))
scheduleFrame()
return
}
_, _ = statusBuffer.Write([]byte(m))
_, _ = floatStatusBuffer.Write([]byte(m))
statusLogged = true
scheduleFrame()
}
@ -170,9 +167,25 @@ func init() {
loadAudioAssets()
etk.Style.TextFont = largeFont
etk.Style.TextFontMutex = fontMutex
etk.Style.TextColorLight = triangleA
etk.Style.TextColorDark = triangleA
etk.Style.InputBgColor = color.RGBA{40, 24, 9, 255}
etk.Style.ScrollAreaColor = color.RGBA{26, 15, 6, 255}
etk.Style.ScrollHandleColor = color.RGBA{180, 154, 108, 255}
etk.Style.ButtonTextColor = color.RGBA{0, 0, 0, 255}
etk.Style.ButtonBgColor = color.RGBA{225, 188, 125, 255}
statusBuffer.SetForegroundColor(bufferTextColor)
statusBuffer.SetBackgroundColor(bufferBackgroundColor)
floatStatusBuffer.SetForegroundColor(bufferTextColor)
floatStatusBuffer.SetBackgroundColor(bufferBackgroundColor)
gameBuffer.SetForegroundColor(bufferTextColor)
gameBuffer.SetBackgroundColor(bufferBackgroundColor)
@ -380,19 +393,6 @@ func initializeFonts() {
if err != nil {
log.Fatal(err)
}
tt, err = opentype.Parse(fonts.PressStart2P_ttf)
if err != nil {
log.Fatal(err)
}
monoFont, err = opentype.NewFace(tt, &opentype.FaceOptions{
Size: monoFontSize,
DPI: dpi,
Hinting: font.HintingNone,
})
if err != nil {
log.Fatal(err)
}
}
func diceImage(roll int) *ebiten.Image {
@ -419,6 +419,7 @@ func setViewBoard(view bool) {
if viewBoard != view {
g := game
g.keyboard.Hide()
g.Board.floatChatGrid.SetVisible(false)
g.connectKeyboardButton.Label.SetText(gotext.Get("Show Keyboard"))
g.lobby.showKeyboardButton.Label.SetText(gotext.Get("Show Keyboard"))
g.Board.showKeyboardButton.Label.SetText(gotext.Get("Show Keyboard"))
@ -439,8 +440,6 @@ func setViewBoard(view bool) {
game.Board.uiGrid.SetRect(game.Board.uiGrid.Rect())
game.Board.bearOffOverlay.SetRect(game.Board.bearOffOverlay.Rect())
game.Board.setKeyboardRect()
} else {
if !game.loggedIn {
game.setRoot(connectGrid)
@ -455,12 +454,6 @@ func setViewBoard(view bool) {
game.Board.menuGrid.SetVisible(false)
game.Board.settingsGrid.SetVisible(false)
game.Board.leaveGameGrid.SetVisible(false)
if !game.loggedIn {
game.keyboard.SetRect(0, game.screenH-game.screenH/3, game.screenW, game.screenH/3)
} else {
game.lobby.setKeyboardRect()
}
}
scheduleFrame()
@ -530,8 +523,6 @@ type Game struct {
cpuProfile *os.File
loaded bool
connectUsername *etk.Input
connectPassword *etk.Input
connectServer *etk.Input
@ -552,6 +543,8 @@ type Game struct {
forceLayout bool
scaleFactor float64
loaded bool
}
func NewGame() *Game {
@ -583,19 +576,6 @@ func NewGame() *Game {
g.keyboard.SetKeys(kibodo.KeysQWERTY)
}
etk.Style.TextFont = mediumFont
etk.Style.TextFontMutex = fontMutex
etk.Style.TextColorLight = triangleA
etk.Style.TextColorDark = triangleA
etk.Style.InputBgColor = color.RGBA{40, 24, 9, 255}
etk.Style.ScrollAreaColor = color.RGBA{26, 15, 6, 255}
etk.Style.ScrollHandleColor = color.RGBA{180, 154, 108, 255}
etk.Style.ButtonTextColor = color.RGBA{0, 0, 0, 255}
etk.Style.ButtonBgColor = color.RGBA{225, 188, 125, 255}
{
headerLabel := etk.NewText(gotext.Get("Welcome to %s", "bgammon.org"))
nameLabel := etk.NewText(gotext.Get("Username"))
@ -1159,6 +1139,24 @@ func (g *Game) Update() error {
if !g.loaded {
g.loaded = true
var updateButtons func(w etk.Widget)
updateButtons = func(w etk.Widget) {
for _, c := range w.Children() {
updateButtons(c)
}
btn, ok := w.(*etk.Button)
if ok && btn != g.Board.showMenuButton {
btn.Label.SetFont(largeFont, fontMutex)
}
}
updateButtons(connectGrid)
updateButtons(game.lobby.buttonsGrid)
updateButtons(game.Board.menuGrid)
updateButtons(game.Board.leaveGameGrid)
updateButtons(game.Board.bearOffOverlay)
updateButtons(game.Board.floatChatGrid)
// Auto-connect
if g.Username != "" || g.Password != "" {
g.Connect()
@ -1339,12 +1337,9 @@ func (g *Game) Draw(screen *ebiten.Image) {
return
}
statusBuffer.Draw(screen)
if !viewBoard { // Lobby
g.lobby.draw(screen)
} else { // Game board
gameBuffer.Draw(screen)
inputBuffer.Draw(screen)
g.Board.Draw(screen)
}
@ -1419,18 +1414,20 @@ func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
}
statusBuffer.SetScrollBarColors(etk.Style.ScrollAreaColor, etk.Style.ScrollHandleColor)
floatStatusBuffer.SetScrollBarColors(etk.Style.ScrollAreaColor, etk.Style.ScrollHandleColor)
gameBuffer.SetScrollBarColors(etk.Style.ScrollAreaColor, etk.Style.ScrollHandleColor)
inputBuffer.Field.SetScrollBarColors(etk.Style.ScrollAreaColor, etk.Style.ScrollHandleColor)
if ShowServerSettings {
connectGrid.SetRowSizes(60, 50, 50, 50, 100, g.scale(baseButtonHeight))
connectGrid.SetRowSizes(60, 50, 50, 50, 108, g.scale(baseButtonHeight))
} else {
connectGrid.SetRowSizes(60, 50, 50, 100, g.scale(baseButtonHeight))
connectGrid.SetRowSizes(60, 50, 50, 108, g.scale(baseButtonHeight))
}
{
scrollBarWidth := g.scale(32)
statusBuffer.SetScrollBarWidth(scrollBarWidth)
floatStatusBuffer.SetScrollBarWidth(scrollBarWidth)
gameBuffer.SetScrollBarWidth(scrollBarWidth)
inputBuffer.Field.SetScrollBarWidth(scrollBarWidth)
}
@ -1503,14 +1500,17 @@ func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
if g.screenW > 200 {
statusBuffer.SetPadding(4)
floatStatusBuffer.SetPadding(4)
gameBuffer.SetPadding(4)
inputBuffer.Field.SetPadding(4)
} else if g.screenW > 100 {
statusBuffer.SetPadding(2)
floatStatusBuffer.SetPadding(2)
gameBuffer.SetPadding(2)
inputBuffer.Field.SetPadding(2)
} else {
statusBuffer.SetPadding(0)
floatStatusBuffer.SetPadding(0)
gameBuffer.SetPadding(0)
inputBuffer.Field.SetPadding(0)
}
@ -1520,6 +1520,8 @@ func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
g.Board.updateOpponentLabel()
g.Board.updatePlayerLabel()
g.keyboard.SetRect(0, game.screenH-game.screenH/3, game.screenW, game.screenH/3)
return outsideWidth, outsideHeight
}
@ -1555,6 +1557,8 @@ func (g *Game) EnableTouchInput() {
*b.matchStatusGrid = *etk.NewGrid()
b.matchStatusGrid.AddChildAt(b.timerLabel, 0, 0, 1, 1)
b.matchStatusGrid.AddChildAt(b.clockLabel, 1, 0, 1, 1)
b.fontUpdated()
}
func (g *Game) toggleProfiling() error {

View file

@ -122,16 +122,11 @@ func (l *lobby) fontUpdated() {
l.lineOffset = m.Ascent.Round()
}
func (l *lobby) setKeyboardRect() {
game.keyboard.SetRect(0, game.screenH-game.screenH/3, game.screenW, game.screenH/3)
}
func (l *lobby) toggleKeyboard() error {
if game.keyboard.Visible() {
game.keyboard.Hide()
l.showKeyboardButton.Label.SetText(gotext.Get("Show Keyboard"))
} else {
l.setKeyboardRect()
game.keyboard.Show()
l.showKeyboardButton.Label.SetText(gotext.Get("Hide Keyboard"))
}
@ -404,10 +399,6 @@ func (l *lobby) setRect(x, y, w, h int) {
return
}
if game.loggedIn && !viewBoard && game.keyboard.Visible() {
l.setKeyboardRect()
}
if game.scaleFactor >= 1.25 {
if l.fontFace != largeFont {
l.fontFace = largeFont

2
go.mod
View file

@ -4,7 +4,7 @@ go 1.17
require (
code.rocket9labs.com/tslocum/bgammon v0.0.0-20231103194829-7e7aed577632
code.rocket9labs.com/tslocum/etk v0.0.0-20231108013751-c8545de5b36f
code.rocket9labs.com/tslocum/etk v0.0.0-20231108221136-e826b3e7fc6b
code.rocketnine.space/tslocum/kibodo v1.0.2
code.rocketnine.space/tslocum/messeji v1.0.6-0.20231108013522-08fa5fbe2882
github.com/hajimehoshi/ebiten/v2 v2.6.2

4
go.sum
View file

@ -1,7 +1,7 @@
code.rocket9labs.com/tslocum/bgammon v0.0.0-20231103194829-7e7aed577632 h1:iHXCwQnu0Ud6LUGiBHx5SwXilcw3RKH8MNJHdmOfjxM=
code.rocket9labs.com/tslocum/bgammon v0.0.0-20231103194829-7e7aed577632/go.mod h1:U8qo60VHGzKFUHLZZJcvT0yDzwWybJBabsCw3Lyqx4s=
code.rocket9labs.com/tslocum/etk v0.0.0-20231108013751-c8545de5b36f h1:S7M+ZNN8qLzYtsm9aQ2BHb0ICbiMNAeTNYvvgl4Zvxk=
code.rocket9labs.com/tslocum/etk v0.0.0-20231108013751-c8545de5b36f/go.mod h1:LRSwJxjKNTzoLhGfR5ZseBecISk9gCYyzmo9HDol+UY=
code.rocket9labs.com/tslocum/etk v0.0.0-20231108221136-e826b3e7fc6b h1:NBboqR87MVzYquA0tgo50CpkMWqchQgJzPUKJArvmQA=
code.rocket9labs.com/tslocum/etk v0.0.0-20231108221136-e826b3e7fc6b/go.mod h1:LRSwJxjKNTzoLhGfR5ZseBecISk9gCYyzmo9HDol+UY=
code.rocketnine.space/tslocum/kibodo v1.0.2 h1:0RfvVz+IUku8MFx9wvDb+p8byns5gAjQLUo4ZenWP44=
code.rocketnine.space/tslocum/kibodo v1.0.2/go.mod h1:mAYs1JKFnWlRFzo9BtteAlwjKdk1MIKgEyhQaPdeQDI=
code.rocketnine.space/tslocum/messeji v1.0.6-0.20231108013522-08fa5fbe2882 h1:/bHhrKySAQogVQaPph6SAi6PY1WCVzYQuWvEGWFxQXw=