Apply device scale factor uniformly

This commit is contained in:
Trevor Slocum 2024-01-21 21:49:35 -08:00
parent 300456e6cf
commit ac2942383f
11 changed files with 270 additions and 318 deletions

View file

@ -21,14 +21,12 @@ func parseFlags() *game.Game {
locale string
tv bool
debug int
touch bool
)
flag.StringVar(&username, "username", "", "Username")
flag.StringVar(&password, "password", "", "Password")
flag.StringVar(&serverAddress, "address", game.DefaultServerAddress, "Server address")
flag.StringVar(&locale, "locale", "", "Use specified locale for translations")
flag.BoolVar(&tv, "tv", false, "Watch random games continuously")
flag.BoolVar(&touch, "touch", false, "Force touch input related interface elements to be displayed")
flag.IntVar(&debug, "debug", 0, "Print debug information and serve pprof on specified port")
flag.Parse()
@ -51,10 +49,6 @@ func parseFlags() *game.Game {
g.ServerAddress = serverAddress
g.TV = tv
if touch {
g.EnableTouchInput()
}
if debug > 0 {
game.Debug = 1
go func() {

View file

@ -172,11 +172,15 @@ var (
)
func NewBoard() *board {
var extraBorder float64
if AutoEnableTouchInput {
extraBorder = float64(etk.Scale(5))
}
b := &board{
barWidth: 100,
triangleOffset: float64(50),
horizontalBorderSize: 20,
verticalBorderSize: float64(baseBoardVerticalSize),
horizontalBorderSize: 20 + extraBorder,
verticalBorderSize: float64(baseBoardVerticalSize) + extraBorder,
overlapSize: 97,
Sprites: &Sprites{
sprites: make([]*Sprite, 30),
@ -333,7 +337,7 @@ func NewBoard() *board {
b.changePasswordGrid.SetBackground(color.RGBA{40, 24, 9, 255})
b.changePasswordGrid.SetColumnSizes(20, -1, -1, 20)
b.changePasswordGrid.SetRowSizes(72, fieldHeight+20+fieldHeight, -1, game.scale(baseButtonHeight))
b.changePasswordGrid.SetRowSizes(72, fieldHeight+20+fieldHeight, -1, etk.Scale(baseButtonHeight))
b.changePasswordGrid.AddChildAt(headerLabel, 1, 0, 2, 1)
b.changePasswordGrid.AddChildAt(fieldGrid, 1, 1, 2, 1)
b.changePasswordGrid.AddChildAt(etk.NewBox(), 1, 2, 1, 1)
@ -493,7 +497,7 @@ func NewBoard() *board {
}
b.settingsGrid.SetBackground(color.RGBA{40, 24, 9, 255})
b.settingsGrid.SetColumnSizes(20, -1, -1, 20)
b.settingsGrid.SetRowSizes(72, -1, 20, game.scale(baseButtonHeight))
b.settingsGrid.SetRowSizes(72, -1, 20, etk.Scale(baseButtonHeight))
b.settingsGrid.AddChildAt(settingsLabel, 1, 0, 2, 1)
b.settingsGrid.AddChildAt(checkboxGrid, 1, 1, 2, 1)
b.settingsGrid.AddChildAt(etk.NewBox(), 1, 2, 1, 1)
@ -626,20 +630,12 @@ func (b *board) fontUpdated() {
b.lineOffset = m.Ascent.Round()
fontMutex.Unlock()
bufferFont := b.fontFace
if game.scaleFactor <= 1 {
switch b.fontFace {
case largeFont:
bufferFont = mediumFont
case mediumFont:
bufferFont = smallFont
}
}
bufferFont := smallFont
statusBuffer.SetFont(bufferFont, fontMutex)
gameBuffer.SetFont(bufferFont, fontMutex)
inputBuffer.Field.SetFont(bufferFont, fontMutex)
if game.TouchInput {
if AutoEnableTouchInput {
b.showMenuButton.Label.SetFont(largeFont, fontMutex)
} else {
b.showMenuButton.Label.SetFont(smallFont, fontMutex)
@ -648,7 +644,7 @@ func (b *board) fontUpdated() {
b.timerLabel.SetFont(b.fontFace, fontMutex)
b.clockLabel.SetFont(b.fontFace, fontMutex)
if game.TouchInput {
if AutoEnableTouchInput {
b.opponentForcedLabel.SetFont(largeFont, fontMutex)
b.playerForcedLabel.SetFont(largeFont, fontMutex)
} else {
@ -659,8 +655,13 @@ func (b *board) fontUpdated() {
b.opponentMovesLabel.SetFont(bufferFont, fontMutex)
b.playerMovesLabel.SetFont(bufferFont, fontMutex)
b.opponentPipCount.SetFont(bufferFont, fontMutex)
b.playerPipCount.SetFont(bufferFont, fontMutex)
if AutoEnableTouchInput {
b.opponentPipCount.SetFont(extraSmallFont, fontMutex)
b.playerPipCount.SetFont(extraSmallFont, fontMutex)
} else {
b.opponentPipCount.SetFont(bufferFont, fontMutex)
b.playerPipCount.SetFont(bufferFont, fontMutex)
}
}
func (b *board) recreateUIGrid() {
@ -675,15 +676,11 @@ func (b *board) recreateUIGrid() {
gridY += 2
}
if game.replay {
f := smallFont
if defaultFontSize == extraLargeFontSize {
f = mediumFont
}
summary1 := etk.NewText("")
summary1.SetFont(f, fontMutex)
summary1.SetFont(smallFont, fontMutex)
summary1.Write(game.replaySummary1)
summary2 := etk.NewText("")
summary2.SetFont(f, fontMutex)
summary2.SetFont(smallFont, fontMutex)
summary2.Write(game.replaySummary2)
subGrid := etk.NewGrid()
subGrid.SetBackground(bufferBackgroundColor)
@ -691,7 +688,7 @@ func (b *board) recreateUIGrid() {
subGrid.AddChildAt(summary1, 1, 0, 1, 1)
g := etk.NewGrid()
g.SetRowSizes(game.scale(baseButtonHeight), int(b.verticalBorderSize/2), -1, int(b.verticalBorderSize/2), lobbyStatusBufferHeight*2)
g.SetRowSizes(etk.Scale(baseButtonHeight), int(b.verticalBorderSize/2), -1, int(b.verticalBorderSize/2), lobbyStatusBufferHeight*2)
g.AddChildAt(b.replayGrid, 0, 0, 1, 1)
g.AddChildAt(subGrid, 0, 2, 1, 1)
g.AddChildAt(statusBuffer, 0, 4, 1, 1)
@ -733,14 +730,14 @@ func (b *board) showButtonGrid(buttonGrid *etk.Grid) {
func (b *board) recreateButtonGrid() {
buttonGrid := func(grid *etk.Grid, reverse bool, widgets ...etk.Widget) *etk.Grid {
w := game.scale(250)
w := etk.Scale(250)
if w > b.innerW/4 {
w = b.innerW / 4
}
if w > b.innerH/4 {
w = b.innerH / 4
}
h := game.scale(125)
h := etk.Scale(125)
if h > b.innerW/8 {
h = b.innerW / 8
}
@ -1791,10 +1788,7 @@ func (b *board) setRect(x, y, w, h int) {
b.updateBackgroundImage()
b.processState()
matchStatus := 36
if game.scaleFactor >= 1.25 || AutoEnableTouchInput {
matchStatus *= 2
}
matchStatus := etk.Scale(36)
if AutoEnableTouchInput {
b.uiGrid.SetRowSizes(int(b.verticalBorderSize/2), matchStatus, int(b.verticalBorderSize/2), fieldHeight, int(b.verticalBorderSize/2), -1, int(b.verticalBorderSize/2), -1)
} else {
@ -1802,11 +1796,11 @@ func (b *board) setRect(x, y, w, h int) {
}
{
dialogWidth := game.scale(620)
dialogWidth := etk.Scale(620)
if dialogWidth > game.screenW {
dialogWidth = game.screenW
}
dialogHeight := game.scale(100)
dialogHeight := etk.Scale(100)
if dialogHeight > game.screenH {
dialogHeight = game.screenH
}
@ -1816,11 +1810,11 @@ func (b *board) setRect(x, y, w, h int) {
}
{
dialogWidth := game.scale(620)
dialogWidth := etk.Scale(620)
if dialogWidth > game.screenW {
dialogWidth = game.screenW
}
dialogHeight := 72 + 72 + 20 + 72 + 20 + 72 + 20 + 72 + 20 + 72 + 20 + 72 + 20 + 72 + 20 + game.scale(baseButtonHeight)
dialogHeight := 72 + 72 + 20 + 72 + 20 + 72 + 20 + 72 + 20 + 72 + 20 + 72 + 20 + 72 + 20 + etk.Scale(baseButtonHeight)
if dialogHeight > game.screenH {
dialogHeight = game.screenH
}
@ -1832,11 +1826,11 @@ func (b *board) setRect(x, y, w, h int) {
}
{
dialogWidth := game.scale(400)
dialogWidth := etk.Scale(400)
if dialogWidth > game.screenW {
dialogWidth = game.screenW
}
dialogHeight := game.scale(100)
dialogHeight := etk.Scale(100)
if dialogHeight > game.screenH {
dialogHeight = game.screenH
}
@ -1850,7 +1844,7 @@ func (b *board) setRect(x, y, w, h int) {
b.recreateButtonGrid()
b.menuGrid.SetColumnSizes(-1, game.scale(10), -1, game.scale(10), -1)
b.menuGrid.SetColumnSizes(-1, etk.Scale(10), -1, etk.Scale(10), -1)
var padding int
if b.w >= 600 {
@ -2619,7 +2613,7 @@ func (b *board) finishDrag(x int, y int, click bool) {
if !b.draggingClick && index == b.draggingSpace && !b.lastDragClick.IsZero() && time.Since(b.lastDragClick) < 500*time.Millisecond {
b.startDrag(dropped, index, true)
if game.TouchInput {
if AutoEnableTouchInput {
r := b.spaceRects[index]
offset := int(b.spaceWidth) + int(b.overlapSize)*4
if !b.bottomRow(index) {

View file

@ -67,10 +67,11 @@ var (
imgDice5 *ebiten.Image
imgDice6 *ebiten.Image
smallFont font.Face
mediumFont font.Face
largeFont font.Face
extraLargeFont font.Face
extraSmallFont font.Face
smallFont font.Face
mediumFont font.Face
mediumLargeFont font.Face
largeFont font.Face
fontMutex = &sync.Mutex{}
)
@ -90,10 +91,11 @@ const (
)
const (
smallFontSize = 20
mediumFontSize = 24
largeFontSize = 36
extraLargeFontSize = 52
extraSmallFontSize = 14
smallFontSize = 20
mediumFontSize = 24
mediumLargeFontSize = 32
largeFontSize = 36
)
var (
@ -128,8 +130,6 @@ var (
historyContainer *etk.Grid
listGamesContainer *etk.Grid
tutorialFrame *etk.Frame
connectFrame *etk.Frame
createGameFrame *etk.Frame
joinGameFrame *etk.Frame
@ -173,46 +173,6 @@ func lg(s string) {
scheduleFrame()
}
func init() {
gotext.SetDomain("boxcars")
initializeFonts()
loadAudioAssets()
if AutoEnableTouchInput {
etk.Bindings.ConfirmRune = 199
etk.Bindings.BackRune = 231
}
if defaultFontSize == extraLargeFontSize {
etk.Style.TextFont = extraLargeFont
} else {
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)
gameBuffer.SetForegroundColor(bufferTextColor)
gameBuffer.SetBackgroundColor(bufferBackgroundColor)
inputBuffer.Field.SetForegroundColor(bufferTextColor)
inputBuffer.Field.SetBackgroundColor(bufferBackgroundColor)
inputBuffer.Field.SetSuffix("")
}
var loadedCheckerWidth = -1
func loadImageAssets(width int) {
@ -229,7 +189,7 @@ func loadImageAssets(width int) {
panic("nil game")
}
maxSize := game.scale(100)
maxSize := etk.Scale(100)
if maxSize > game.screenW/10 {
maxSize = game.screenW / 10
}
@ -237,7 +197,7 @@ func loadImageAssets(width int) {
maxSize = game.screenH / 10
}
diceSize = game.scale(width)
diceSize = etk.Scale(width)
if diceSize > maxSize {
diceSize = maxSize
}
@ -387,8 +347,21 @@ func initializeFonts() {
}
const dpi = 72
s := etk.ScaleFactor()
if AutoEnableTouchInput {
s /= 2
}
extraSmallFont, err = opentype.NewFace(tt, &opentype.FaceOptions{
Size: extraSmallFontSize * s,
DPI: dpi,
Hinting: font.HintingFull,
})
if err != nil {
log.Fatal(err)
}
smallFont, err = opentype.NewFace(tt, &opentype.FaceOptions{
Size: smallFontSize,
Size: smallFontSize * s,
DPI: dpi,
Hinting: font.HintingFull,
})
@ -396,7 +369,15 @@ func initializeFonts() {
log.Fatal(err)
}
mediumFont, err = opentype.NewFace(tt, &opentype.FaceOptions{
Size: mediumFontSize,
Size: mediumFontSize * s,
DPI: dpi,
Hinting: font.HintingFull,
})
if err != nil {
log.Fatal(err)
}
mediumLargeFont, err = opentype.NewFace(tt, &opentype.FaceOptions{
Size: mediumLargeFontSize * s,
DPI: dpi,
Hinting: font.HintingFull,
})
@ -404,15 +385,7 @@ func initializeFonts() {
log.Fatal(err)
}
largeFont, err = opentype.NewFace(tt, &opentype.FaceOptions{
Size: largeFontSize,
DPI: dpi,
Hinting: font.HintingFull,
})
if err != nil {
log.Fatal(err)
}
extraLargeFont, err = opentype.NewFace(tt, &opentype.FaceOptions{
Size: extraLargeFontSize,
Size: largeFontSize * s,
DPI: dpi,
Hinting: font.HintingFull,
})
@ -597,7 +570,6 @@ type Game struct {
pressedRunes []rune
cursorX, cursorY int
TouchInput bool
rootWidget etk.Widget
@ -607,8 +579,6 @@ type Game struct {
forceLayout bool
scaleFactor float64
bufferWidth int
connectGridY int
@ -618,13 +588,10 @@ type Game struct {
needLayoutLobby bool
needLayoutBoard bool
loadedConnect bool
loadedLobby bool
loadedBoard bool
LoadReplay []byte
loaded bool
initialized bool
loaded bool
showRegister bool
showReset bool
@ -651,31 +618,62 @@ func NewGame() *Game {
g := &Game{
runeBuffer: make([]rune, 24),
TouchInput: AutoEnableTouchInput,
tutorialFrame: etk.NewFrame(),
debugImg: ebiten.NewImage(200, 200),
volume: 1,
scaleFactor: 1,
debugImg: ebiten.NewImage(200, 200),
volume: 1,
Mutex: &sync.Mutex{},
}
g.tutorialFrame.SetPositionChildren(true)
game = g
return g
}
func (g *Game) initialize() {
gotext.SetDomain("boxcars")
initializeFonts()
loadAudioAssets()
loadImageAssets(0)
if AutoEnableTouchInput {
etk.Bindings.ConfirmRune = 199
etk.Bindings.BackRune = 231
}
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)
gameBuffer.SetForegroundColor(bufferTextColor)
gameBuffer.SetBackgroundColor(bufferBackgroundColor)
inputBuffer.Field.SetForegroundColor(bufferTextColor)
inputBuffer.Field.SetBackgroundColor(bufferBackgroundColor)
inputBuffer.Field.SetSuffix("")
g.Board = NewBoard()
g.lobby = NewLobby()
xPadding := 10
yPadding := 20
labelWidth := 200
if defaultFontSize == extraLargeFontSize {
xPadding = 15
yPadding = 30
labelWidth = 260
xPadding := etk.Scale(10)
yPadding := etk.Scale(20)
labelWidth := etk.Scale(200)
if AutoEnableTouchInput {
labelWidth /= 2
}
connectAddress := game.ServerAddress
@ -818,6 +816,10 @@ func NewGame() *Game {
nameLabel := newCenteredText(gotext.Get("Username"))
passwordLabel := newCenteredText(gotext.Get("Password"))
serverLabel := newCenteredText(gotext.Get("Server"))
if AutoEnableTouchInput {
headerLabel.SetFont(mediumLargeFont, fontMutex)
headerLabel.SetHorizontal(messeji.AlignCenter)
}
infoLabel := etk.NewText(gotext.Get("To log in as a guest, enter a username (if you want) and do not enter a password."))
@ -1048,10 +1050,10 @@ func NewGame() *Game {
opponentLabel := newCenteredText(gotext.Get("Opponent"))
opponentLabel.SetFollow(false)
opponentLabel.SetScrollBarVisible(false)
indentA, indentB := lobbyIndentA, lobbyIndentB
if defaultFontSize == extraLargeFontSize {
indentA, indentB = int(float64(indentA)*1.3), int(float64(indentB)*1.3)
if AutoEnableTouchInput {
dateLabel.SetFont(mediumFont, fontMutex)
resultLabel.SetFont(mediumFont, fontMutex)
opponentLabel.SetFont(mediumFont, fontMutex)
}
g.lobby.historyUsername = etk.NewInput("", "", func(text string) (handled bool) {
@ -1063,7 +1065,13 @@ func NewGame() *Game {
searchButton := etk.NewButton(gotext.Get("Search"), g.selectHistorySearch)
g.lobby.historyList = etk.NewList(game.itemHeight(), g.lobby.selectHistory)
indentA, indentB := etk.Scale(lobbyIndentA), etk.Scale(lobbyIndentB)
historyItemHeight := game.itemHeight()
if AutoEnableTouchInput {
historyItemHeight /= 2
}
g.lobby.historyList = etk.NewList(historyItemHeight, g.lobby.selectHistory)
g.lobby.historyList.SetColumnSizes(int(float64(indentA)*1.25), int(float64(indentB)*1.25)-int(float64(indentA)*1.25), -1)
g.lobby.historyList.SetHighlightColor(color.RGBA{79, 55, 30, 255})
@ -1090,10 +1098,7 @@ func NewGame() *Game {
g.lobby.historyRatingCasualTabulaMulti = newLabel("...", messeji.AlignStart)
ratingGrid := func(singleLabel *etk.Text, multiLabel *etk.Text) *etk.Grid {
dividerSize := 10
if defaultFontSize == extraLargeFontSize {
dividerSize = 20
}
const dividerSize = 10
g := etk.NewGrid()
g.SetColumnSizes(-1, dividerSize, -1)
g.AddChildAt(newLabel(gotext.Get("Single"), messeji.AlignEnd), 0, 0, 1, 1)
@ -1106,12 +1111,6 @@ func NewGame() *Game {
historyDividerLine := etk.NewBox()
historyDividerLine.SetBackground(bufferTextColor)
headerLabel := func(text string) *etk.Text {
t := newLabel(text, messeji.AlignCenter)
t.SetFont(extraLargeFont, fontMutex)
return t
}
g.lobby.historyPageLabel = newLabel("...", messeji.AlignCenter)
pageControlGrid := etk.NewGrid()
@ -1122,11 +1121,11 @@ func NewGame() *Game {
historyRatingGrid := etk.NewGrid()
historyRatingGrid.SetRowSizes(2, -1, -1, -1)
historyRatingGrid.AddChildAt(historyDividerLine, 0, 0, 3, 1)
historyRatingGrid.AddChildAt(headerLabel(gotext.Get("Backgammon")), 0, 1, 1, 1)
historyRatingGrid.AddChildAt(newLabel(gotext.Get("Backgammon"), messeji.AlignCenter), 0, 1, 1, 1)
historyRatingGrid.AddChildAt(ratingGrid(g.lobby.historyRatingCasualBackgammonSingle, g.lobby.historyRatingCasualBackgammonMulti), 0, 2, 1, 2)
historyRatingGrid.AddChildAt(headerLabel(gotext.Get("Acey-deucey")), 1, 1, 1, 1)
historyRatingGrid.AddChildAt(newLabel(gotext.Get("Acey-deucey"), messeji.AlignCenter), 1, 1, 1, 1)
historyRatingGrid.AddChildAt(ratingGrid(g.lobby.historyRatingCasualAceySingle, g.lobby.historyRatingCasualAceyMulti), 1, 2, 1, 2)
historyRatingGrid.AddChildAt(headerLabel(gotext.Get("Tabula")), 2, 1, 1, 1)
historyRatingGrid.AddChildAt(newLabel(gotext.Get("Tabula"), messeji.AlignCenter), 2, 1, 1, 1)
historyRatingGrid.AddChildAt(ratingGrid(g.lobby.historyRatingCasualTabulaSingle, g.lobby.historyRatingCasualTabulaMulti), 2, 2, 1, 2)
historyContainer = etk.NewGrid()
@ -1162,15 +1161,18 @@ func NewGame() *Game {
nameLabel := newCenteredText(gotext.Get("Match Name"))
nameLabel.SetFollow(false)
nameLabel.SetScrollBarVisible(false)
indentA, indentB := lobbyIndentA, lobbyIndentB
if defaultFontSize == extraLargeFontSize {
indentA, indentB = int(float64(indentA)*1.3), int(float64(indentB)*1.3)
if AutoEnableTouchInput {
statusLabel.SetFont(mediumFont, fontMutex)
ratingLabel.SetFont(mediumFont, fontMutex)
pointsLabel.SetFont(mediumFont, fontMutex)
nameLabel.SetFont(mediumFont, fontMutex)
}
g.lobby.historyButton = etk.NewButton(gotext.Get("History"), game.selectHistory)
g.lobby.historyButton.SetVisible(false)
indentA, indentB := etk.Scale(lobbyIndentA), etk.Scale(lobbyIndentB)
headerGrid := etk.NewGrid()
headerGrid.SetColumnSizes(indentA, indentB-indentA, indentB-indentA, -1, 300)
headerGrid.AddChildAt(statusLabel, 0, 0, 1, 1)
@ -1197,6 +1199,21 @@ func NewGame() *Game {
g.keyboardHint.SetVertical(messeji.AlignCenter)
}
statusBuffer.SetScrollBarColors(etk.Style.ScrollAreaColor, etk.Style.ScrollHandleColor)
gameBuffer.SetScrollBarColors(etk.Style.ScrollAreaColor, etk.Style.ScrollHandleColor)
inputBuffer.Field.SetScrollBarColors(etk.Style.ScrollAreaColor, etk.Style.ScrollHandleColor)
g.lobby.availableMatchesList.SetScrollBarColors(etk.Style.ScrollAreaColor, etk.Style.ScrollHandleColor)
g.lobby.historyList.SetScrollBarColors(etk.Style.ScrollAreaColor, etk.Style.ScrollHandleColor)
{
scrollBarWidth := etk.Scale(32)
statusBuffer.SetScrollBarWidth(scrollBarWidth)
gameBuffer.SetScrollBarWidth(scrollBarWidth)
inputBuffer.Field.SetScrollBarWidth(scrollBarWidth)
g.lobby.availableMatchesList.SetScrollBarWidth(scrollBarWidth)
g.lobby.historyList.SetScrollBarWidth(scrollBarWidth)
}
g.needLayoutConnect = true
g.needLayoutLobby = true
g.needLayoutBoard = true
@ -1215,7 +1232,6 @@ func NewGame() *Game {
go g.handleUpdateTimeLabels()
scheduleFrame()
return g
}
func (g *Game) playOffline() {
@ -1292,17 +1308,17 @@ func (g *Game) setRoot(w etk.Widget) {
}
func (g *Game) setBufferRects() {
statusBufferHeight := g.scale(75)
historyRatingHeight := 200
if defaultFontSize == extraLargeFontSize {
historyRatingHeight = 250
}
statusBufferHeight := etk.Scale(75)
historyRatingHeight := etk.Scale(200)
createGameContainer.SetRowSizes(-1, statusBufferHeight, g.lobby.buttonBarHeight)
joinGameContainer.SetRowSizes(-1, statusBufferHeight, g.lobby.buttonBarHeight)
historyContainer.SetRowSizes(g.itemHeight(), 2, -1, g.lobby.buttonBarHeight, historyRatingHeight, statusBufferHeight, g.lobby.buttonBarHeight)
listGamesContainer.SetRowSizes(g.itemHeight(), 2, -1, statusBufferHeight, g.lobby.buttonBarHeight)
listHeaderHeight := g.itemHeight()
if AutoEnableTouchInput {
listHeaderHeight /= 2
}
listGamesContainer.SetRowSizes(listHeaderHeight, 2, -1, statusBufferHeight, g.lobby.buttonBarHeight)
}
func (g *Game) handleAutoRefresh() {
@ -1592,9 +1608,17 @@ func (g *Game) handleEvent(e interface{}) {
if match.Winner == 2 {
result = "L"
}
list.AddChildAt(newCenteredText(time.Unix(match.Timestamp, 0).Format("2006-01-02")), 0, y+i)
list.AddChildAt(newCenteredText(result), 1, y+i)
list.AddChildAt(newCenteredText(match.Opponent), 2, y+i)
dateLabel := newCenteredText(time.Unix(match.Timestamp, 0).Format("2006-01-02"))
resultLabel := newCenteredText(result)
opponentLabel := newCenteredText(match.Opponent)
if AutoEnableTouchInput {
dateLabel.SetFont(mediumFont, fontMutex)
resultLabel.SetFont(mediumFont, fontMutex)
opponentLabel.SetFont(mediumFont, fontMutex)
}
list.AddChildAt(dateLabel, 0, y+i)
list.AddChildAt(resultLabel, 1, y+i)
list.AddChildAt(opponentLabel, 2, y+i)
}
if ev.Page == 1 {
list.SetSelectedItem(0, 0)
@ -2202,9 +2226,14 @@ func (g *Game) selectConnect() error {
}
func (g *Game) searchMatches(username string) {
loadingText := newCenteredText(gotext.Get("Loading..."))
if AutoEnableTouchInput {
loadingText.SetFont(mediumFont, fontMutex)
}
g.lobby.historyList.Clear()
g.lobby.historyList.SetSelectionMode(etk.SelectNone)
g.lobby.historyList.AddChildAt(newCenteredText(gotext.Get("Loading...")), 0, 0)
g.lobby.historyList.AddChildAt(loadingText, 0, 0)
g.Client.Out <- []byte(fmt.Sprintf("history %s", username))
}
@ -2248,7 +2277,6 @@ func (g *Game) handleInput(keys []ebiten.Key) error {
return nil
} else if AutoEnableTouchInput {
scheduleFrame()
log.Println("SCHEDULE FRAME ON KEYS")
}
if !g.loggedIn {
@ -2439,7 +2467,6 @@ func (g *Game) Update() error {
g.pressedKeys = inpututil.AppendPressedKeys(g.pressedKeys[:0])
if len(g.pressedKeys) > 0 {
log.Printf("PRESSED %+v", g.pressedKeys)
scheduleFrame()
}
@ -2472,7 +2499,6 @@ func (g *Game) Update() error {
if cx == 0 && cy == 0 {
g.touchIDs = inpututil.AppendJustPressedTouchIDs(g.touchIDs[:0])
for _, id := range g.touchIDs {
g.EnableTouchInput()
cx, cy = ebiten.TouchPosition(id)
if cx != 0 || cy != 0 {
if g.handleTouch(image.Point{cx, cy}) {
@ -2493,18 +2519,10 @@ func (g *Game) Update() error {
if AutoEnableTouchInput {
g.pressedRunes = ebiten.AppendInputChars(g.pressedRunes[:0])
if len(g.pressedRunes) != 0 {
log.Printf("PRESSED RUNES %+v", g.pressedRunes)
scheduleFrame()
}
}
if !g.TouchInput {
g.touchIDs = inpututil.AppendJustPressedTouchIDs(g.touchIDs[:0])
if len(g.touchIDs) > 0 {
g.EnableTouchInput()
}
}
if len(ebiten.AppendTouchIDs(g.touchIDs[:0])) != 0 {
scheduleFrame()
}
@ -2622,8 +2640,9 @@ func (g *Game) Draw(screen *ebiten.Image) {
g.spinnerIndex = 0
}
if g.scaleFactor != 1.0 {
g.drawBuffer.Write([]byte(fmt.Sprintf("SCA %0.1f\n", g.scaleFactor)))
scale := etk.ScaleFactor()
if scale != 1.0 {
g.drawBuffer.Write([]byte(fmt.Sprintf("SCA %0.1f\n", scale)))
}
g.drawBuffer.Write([]byte(fmt.Sprintf("FPS %c %0.0f", spinner[g.spinnerIndex], ebiten.ActualFPS())))
@ -2648,44 +2667,32 @@ func (g *Game) portraitView() bool {
return g.screenH-g.screenW >= 100
}
func (g *Game) scale(v int) int {
return int(float64(v) * g.scaleFactor)
}
func (g *Game) layoutConnect() {
g.needLayoutConnect = false
infoHeight := 108
if defaultFontSize == extraLargeFontSize {
infoHeight = 108 * 2
headerHeight := etk.Scale(60)
infoHeight := etk.Scale(108)
if AutoEnableTouchInput {
headerHeight = etk.Scale(20)
}
if ShowServerSettings {
connectGrid.SetRowSizes(60, fieldHeight, fieldHeight, fieldHeight, g.scale(baseButtonHeight), g.scale(baseButtonHeight), infoHeight)
registerGrid.SetRowSizes(60, fieldHeight, fieldHeight, fieldHeight, fieldHeight, g.scale(baseButtonHeight), infoHeight)
resetGrid.SetRowSizes(60, fieldHeight, fieldHeight, g.scale(baseButtonHeight), infoHeight)
connectGrid.SetRowSizes(headerHeight, fieldHeight, fieldHeight, fieldHeight, etk.Scale(baseButtonHeight), etk.Scale(baseButtonHeight), infoHeight)
registerGrid.SetRowSizes(headerHeight, fieldHeight, fieldHeight, fieldHeight, fieldHeight, etk.Scale(baseButtonHeight), infoHeight)
resetGrid.SetRowSizes(headerHeight, fieldHeight, fieldHeight, etk.Scale(baseButtonHeight), infoHeight)
} else {
connectGrid.SetRowSizes(60, fieldHeight, fieldHeight, g.scale(baseButtonHeight), g.scale(baseButtonHeight), infoHeight)
registerGrid.SetRowSizes(60, fieldHeight, fieldHeight, fieldHeight, g.scale(baseButtonHeight), infoHeight)
resetGrid.SetRowSizes(60, fieldHeight, g.scale(baseButtonHeight), infoHeight)
}
if !g.loadedConnect {
updateAllButtons(connectGrid)
g.loadedConnect = true
connectGrid.SetRowSizes(headerHeight, fieldHeight, fieldHeight, etk.Scale(baseButtonHeight), etk.Scale(baseButtonHeight), infoHeight)
registerGrid.SetRowSizes(headerHeight, fieldHeight, fieldHeight, fieldHeight, etk.Scale(baseButtonHeight), infoHeight)
resetGrid.SetRowSizes(headerHeight, fieldHeight, etk.Scale(baseButtonHeight), infoHeight)
}
}
func (g *Game) layoutLobby() {
g.needLayoutLobby = false
g.lobby.buttonBarHeight = g.scale(baseButtonHeight)
g.lobby.buttonBarHeight = etk.Scale(baseButtonHeight)
g.lobby.rebuildButtonsGrid()
g.setBufferRects()
if !g.loadedLobby {
updateAllButtons(game.lobby.buttonsGrid)
g.loadedLobby = true
}
}
func (g *Game) layoutBoard() {
@ -2719,12 +2726,6 @@ func (g *Game) layoutBoard() {
g.setBufferRects()
g.Board.widget.SetRect(image.Rect(0, 0, g.screenW, g.screenH))
if !g.loadedBoard {
updateAllButtons(game.Board.menuGrid)
updateAllButtons(game.Board.leaveGameGrid)
g.loadedBoard = true
}
}
func (g *Game) bufferPadding() int {
@ -2741,8 +2742,14 @@ func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
g.Lock()
defer g.Unlock()
s := ebiten.DeviceScaleFactor()
outsideWidth, outsideHeight = int(float64(outsideWidth)*s), int(float64(outsideHeight)*s)
if !g.initialized {
g.initialize()
g.initialized = true
}
originalWidth, originalHeight := outsideWidth, outsideHeight
outsideWidth, outsideHeight = etk.Scale(outsideWidth), etk.Scale(outsideHeight)
if outsideWidth < minWidth {
outsideWidth = minWidth
}
@ -2755,37 +2762,8 @@ func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
g.forceLayout = false
g.screenW, g.screenH = outsideWidth, outsideHeight
g.scaleFactor = s
scheduleFrame()
b := g.Board
if s >= 1.25 {
lobbyStatusBufferHeight = int(50 * s)
g.Board.verticalBorderSize = baseBoardVerticalSize * 1.5
if b.fontFace != largeFont {
b.fontFace = largeFont
b.fontUpdated()
}
} else {
if b.fontFace != mediumFont {
b.fontFace = mediumFont
b.fontUpdated()
}
}
statusBuffer.SetScrollBarColors(etk.Style.ScrollAreaColor, etk.Style.ScrollHandleColor)
gameBuffer.SetScrollBarColors(etk.Style.ScrollAreaColor, etk.Style.ScrollHandleColor)
inputBuffer.Field.SetScrollBarColors(etk.Style.ScrollAreaColor, etk.Style.ScrollHandleColor)
g.lobby.availableMatchesList.SetScrollBarColors(etk.Style.ScrollAreaColor, etk.Style.ScrollHandleColor)
g.lobby.historyList.SetScrollBarColors(etk.Style.ScrollAreaColor, etk.Style.ScrollHandleColor)
{
scrollBarWidth := g.scale(32)
statusBuffer.SetScrollBarWidth(scrollBarWidth)
gameBuffer.SetScrollBarWidth(scrollBarWidth)
inputBuffer.Field.SetScrollBarWidth(scrollBarWidth)
}
fontMutex.Lock()
g.bufferWidth = etk.BoundString(g.Board.fontFace, strings.Repeat("A", bufferCharacterWidth)).Dx()
fontMutex.Unlock()
@ -2793,7 +2771,7 @@ func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
g.bufferWidth = int(float64(g.screenW) * maxStatusWidthRatio)
}
etk.Layout(g.screenW, g.screenH)
etk.Layout(originalWidth, originalHeight)
g.needLayoutConnect = true
g.needLayoutLobby = true
@ -2859,27 +2837,7 @@ func acceptInput(text string) (handled bool) {
}
func (g *Game) itemHeight() int {
if defaultFontSize == extraLargeFontSize {
return 72
}
return 48
}
func (g *Game) EnableTouchInput() {
if g.TouchInput {
return
}
g.TouchInput = true
// Update layout.
g.forceLayout = true
b := g.Board
b.matchStatusGrid.Clear()
b.matchStatusGrid.AddChildAt(b.timerLabel, 0, 0, 1, 1)
b.matchStatusGrid.AddChildAt(b.clockLabel, 1, 0, 1, 1)
b.fontUpdated()
return etk.Scale(48)
}
func (g *Game) toggleProfiling() error {
@ -3071,27 +3029,7 @@ func newCenteredText(text string) *etk.Text {
func centerInput(input *etk.Input) {
input.Field.SetVertical(messeji.AlignCenter)
paddingSize := 5
if defaultFontSize == extraLargeFontSize {
paddingSize = 20
}
input.Field.SetPadding(paddingSize)
}
func updateAllButtons(w etk.Widget) {
for _, c := range w.Children() {
updateAllButtons(c)
}
f := largeFont
if defaultFontSize == extraLargeFontSize {
f = extraLargeFont
}
btn, ok := w.(*etk.Button)
if ok && (defaultFontSize == extraLargeFontSize || btn != game.Board.showMenuButton) {
btn.Label.SetFont(f, fontMutex)
}
input.Field.SetPadding(etk.Scale(5))
}
// Short description.

View file

@ -24,7 +24,6 @@ const (
ShowServerSettings = true
APPNAME = "boxcars-android"
fieldHeight = 100
defaultFontSize = extraLargeFontSize
)
func init() {

View file

@ -21,7 +21,6 @@ const (
ShowServerSettings = false
APPNAME = "boxcars"
fieldHeight = 50
defaultFontSize = largeFontSize
)
func DefaultLocale() string {

View file

@ -17,7 +17,6 @@ const (
ShowServerSettings = false
APPNAME = "boxcars"
fieldHeight = 50
defaultFontSize = largeFontSize
)
func DefaultLocale() string {

View file

@ -31,19 +31,22 @@ const (
lobbyButtonHistoryView
)
const (
var (
lobbyIndentA = 200
lobbyIndentB = 350
)
type lobbyButton struct {
label string
func init() {
if AutoEnableTouchInput {
lobbyIndentA, lobbyIndentB = lobbyIndentA/3, lobbyIndentB/3
}
}
var mainButtons []*lobbyButton
var createButtons []*lobbyButton
var cancelJoinButtons []*lobbyButton
var historyButtons []*lobbyButton
var mainButtons []string
var mainShortButtons []string
var createButtons []string
var cancelJoinButtons []string
var historyButtons []string
type lobby struct {
buttonBarHeight int
@ -94,26 +97,32 @@ type lobby struct {
}
func NewLobby() *lobby {
mainButtons = []*lobbyButton{
{gotext.Get("Refresh matches")},
{gotext.Get("Create match")},
{gotext.Get("Join match")},
mainButtons = []string{
gotext.Get("Refresh matches"),
gotext.Get("Create match"),
gotext.Get("Join match"),
}
createButtons = []*lobbyButton{
{gotext.Get("Cancel")},
{gotext.Get("Create match")},
mainShortButtons = []string{
gotext.Get("Refresh"),
gotext.Get("Create"),
gotext.Get("Join"),
}
cancelJoinButtons = []*lobbyButton{
{gotext.Get("Cancel")},
{gotext.Get("Join match")},
createButtons = []string{
gotext.Get("Cancel"),
gotext.Get("Create match"),
}
historyButtons = []*lobbyButton{
{gotext.Get("Return")},
{gotext.Get("Download replay")},
{gotext.Get("View replay")},
cancelJoinButtons = []string{
gotext.Get("Cancel"),
gotext.Get("Join match"),
}
historyButtons = []string{
gotext.Get("Return"),
gotext.Get("Download replay"),
gotext.Get("View replay"),
}
l := &lobby{
@ -121,16 +130,18 @@ func NewLobby() *lobby {
buttonsGrid: etk.NewGrid(),
}
indentA, indentB := lobbyIndentA, lobbyIndentB
if defaultFontSize == extraLargeFontSize {
indentA, indentB = int(float64(indentA)*1.3), int(float64(indentB)*1.3)
loadingText := newCenteredText(gotext.Get("Loading..."))
if AutoEnableTouchInput {
loadingText.SetFont(mediumFont, fontMutex)
}
indentA, indentB := etk.Scale(lobbyIndentA), etk.Scale(lobbyIndentB)
matchList := etk.NewList(game.itemHeight(), l.selectMatch)
matchList.SetSelectionMode(etk.SelectRow)
matchList.SetColumnSizes(indentA, indentB-indentA, indentB-indentA, -1)
matchList.SetHighlightColor(color.RGBA{79, 55, 30, 255})
matchList.AddChildAt(newCenteredText(gotext.Get("Loading...")), 0, 0)
matchList.AddChildAt(loadingText, 0, 0)
l.availableMatchesList = matchList
return l
}
@ -178,6 +189,9 @@ func (l *lobby) setGameList(games []bgammon.GameListing) {
txt.SetScrollBarVisible(false)
txt.SetWordWrap(false)
txt.SetVertical(messeji.AlignCenter)
if AutoEnableTouchInput {
txt.SetFont(mediumFont, fontMutex)
}
return txt
}
@ -198,10 +212,14 @@ func (l *lobby) setGameList(games []bgammon.GameListing) {
} else {
rating = fmt.Sprintf("%d", entry.Rating)
}
nameLabel := newLabel(entry.Name)
if AutoEnableTouchInput {
nameLabel.SetWordWrap(true)
}
l.availableMatchesList.AddChildAt(newLabel(status), 0, i)
l.availableMatchesList.AddChildAt(newLabel(rating), 1, i)
l.availableMatchesList.AddChildAt(newLabel(fmt.Sprintf("%d", entry.Points)), 2, i)
l.availableMatchesList.AddChildAt(newLabel(entry.Name), 3, i)
l.availableMatchesList.AddChildAt(nameLabel, 3, i)
}
if lastSelection >= 0 && lastSelection < len(l.games) {
@ -214,13 +232,15 @@ func (l *lobby) setGameList(games []bgammon.GameListing) {
}
}
func (l *lobby) getButtons() []*lobbyButton {
func (l *lobby) getButtons() []string {
if l.showCreateGame {
return createButtons
} else if l.showJoinGame {
return cancelJoinButtons
} else if l.showHistory {
return historyButtons
} else if AutoEnableTouchInput && game.portraitView() {
return mainShortButtons
}
return mainButtons
}
@ -350,8 +370,8 @@ func (l *lobby) rebuildButtonsGrid() {
r := l.buttonsGrid.Rect()
l.buttonsGrid.Clear()
for i, btn := range l.getButtons() {
l.buttonsGrid.AddChildAt(etk.NewButton(btn.label, l.selectButton(i)), i, 0, 1, 1)
for i, label := range l.getButtons() {
l.buttonsGrid.AddChildAt(etk.NewButton(label, l.selectButton(i)), i, 0, 1, 1)
}
l.buttonsGrid.SetRect(r)

View file

@ -70,6 +70,9 @@ msgstr ""
msgid "Connecting..."
msgstr ""
msgid "Create"
msgstr ""
msgid "Create Match"
msgstr ""
@ -142,6 +145,9 @@ msgstr ""
msgid "Instant"
msgstr ""
msgid "Join"
msgstr ""
msgid "Join match"
msgstr ""
@ -232,6 +238,9 @@ msgstr ""
msgid "Reconnecting"
msgstr ""
msgid "Refresh"
msgstr ""
msgid "Refresh matches"
msgstr ""

View file

@ -102,13 +102,13 @@ func (w *tutorialWidget) setPage(page int) {
}
message = title + "\n\n" + message
w.grid.SetColumnSizes(-1, -1, -1, -1)
w.grid.SetColumnSizes(-1, -1, -1, -1, -1, -1)
w.grid.SetRowSizes(-1, -1, -1, -1)
w.grid.AddChildAt(w.newTutorialBox(), 0, 0, 4, 1)
w.grid.AddChildAt(w.newTutorialBox(), 0, 0, 6, 1)
w.grid.AddChildAt(w.newTutorialBox(), 0, 1, 1, 2)
w.grid.AddChildAt(w.dialogText(message), 1, 1, 2, 2)
w.grid.AddChildAt(w.newTutorialBox(), 3, 1, 1, 2)
w.grid.AddChildAt(w.newTutorialBox(), 0, 3, 4, 1)
w.grid.AddChildAt(w.dialogText(message), 1, 1, 4, 2)
w.grid.AddChildAt(w.newTutorialBox(), 5, 1, 1, 2)
w.grid.AddChildAt(w.newTutorialBox(), 0, 3, 6, 1)
}
type tutorialDialog struct {

2
go.mod
View file

@ -5,7 +5,7 @@ go 1.17
require (
code.rocket9labs.com/tslocum/bgammon v0.0.0-20240117214045-3607efee4129
code.rocket9labs.com/tslocum/bgammon-tabula-bot v0.0.0-20240120074310-6968c426a4e1
code.rocket9labs.com/tslocum/etk v0.0.0-20240122001849-b8e1658b3f49
code.rocket9labs.com/tslocum/etk v0.0.0-20240122050631-9e17ce631967
code.rocket9labs.com/tslocum/tabula v0.0.0-20240118055336-21a3dea3f702
github.com/hajimehoshi/ebiten/v2 v2.6.3
github.com/leonelquinteros/gotext v1.5.3-0.20231003122255-12a99145a351

4
go.sum
View file

@ -4,8 +4,8 @@ code.rocket9labs.com/tslocum/bgammon v0.0.0-20240117214045-3607efee4129 h1:wguf0
code.rocket9labs.com/tslocum/bgammon v0.0.0-20240117214045-3607efee4129/go.mod h1:LAki3jpHOsr4fwaK0xC9tkg+wgu/9ZNEqqx1zE3/HP4=
code.rocket9labs.com/tslocum/bgammon-tabula-bot v0.0.0-20240120074310-6968c426a4e1 h1:FsUNZJjzoYixG36Hxf0eYov0no6GGWjEVdmvGWjol7Y=
code.rocket9labs.com/tslocum/bgammon-tabula-bot v0.0.0-20240120074310-6968c426a4e1/go.mod h1:w6xR2lWW3xUo7KlCOaJ+Jbs29AfQVRQEJ2W1vb0IuOo=
code.rocket9labs.com/tslocum/etk v0.0.0-20240122001849-b8e1658b3f49 h1:OcdDIzebupJx2uj6lKw6uip537C+RTa39RBpsvOErPc=
code.rocket9labs.com/tslocum/etk v0.0.0-20240122001849-b8e1658b3f49/go.mod h1:2IXUt2b3de6r0IX5W5uR1vvTw1Z+JcX/ATC1woaaW2E=
code.rocket9labs.com/tslocum/etk v0.0.0-20240122050631-9e17ce631967 h1:1utGdjqNQg+7hrduWOfqQpiBeRpbinCrY7mZZi+y7oI=
code.rocket9labs.com/tslocum/etk v0.0.0-20240122050631-9e17ce631967/go.mod h1:2IXUt2b3de6r0IX5W5uR1vvTw1Z+JcX/ATC1woaaW2E=
code.rocket9labs.com/tslocum/tabula v0.0.0-20240118055336-21a3dea3f702 h1:NGZILSBynzLZF84WKZyAuoWsZFq37uvEcP2dFvPsY/8=
code.rocket9labs.com/tslocum/tabula v0.0.0-20240118055336-21a3dea3f702/go.mod h1:WEJXESKXqrMFLAArikQ79lpRibNeeE1C0VruxXYMF5M=
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=