Spit and polish
UI improvements specifically for mobile (running the game with the `-w mobile` or `-w landscape` options) screen sizes. * Rework the Settings window to be mobile friendly to landscape oriented screens (`doodle -w landscape`) and migrate Options tab to magicform. * The toolbar in the Editor will be a single column of buttons on small screens, such as `-w mobile` (375x812) portrait mode smartphone. On larger screens the toolbar shows in two columns of buttons. * Fix tooltips not drawing on top. * Centralize the hard-coded references to specific font filenames * Add cheat code: `test load screen` to bring a sample loading screen up for a few seconds. It needs improvement on `-w landscape`
This commit is contained in:
parent
77297fd60d
commit
44122d4130
|
@ -31,4 +31,5 @@ var (
|
||||||
CheatPlayAsThief = "play as thief"
|
CheatPlayAsThief = "play as thief"
|
||||||
CheatPlayAsAnvil = "megaton weight"
|
CheatPlayAsAnvil = "megaton weight"
|
||||||
CheatGodMode = "god mode"
|
CheatGodMode = "god mode"
|
||||||
|
CheatDebugLoadScreen = "test load screen"
|
||||||
)
|
)
|
||||||
|
|
|
@ -16,7 +16,7 @@ var (
|
||||||
***************/
|
***************/
|
||||||
|
|
||||||
// Debug overlay (FPS etc.) settings.
|
// Debug overlay (FPS etc.) settings.
|
||||||
DebugFontFilename = "DejaVuSans-Bold.ttf"
|
DebugFontFilename = SansBoldFont
|
||||||
DebugFontSize = 16
|
DebugFontSize = 16
|
||||||
DebugLabelColor = render.MustHexColor("#FF9900")
|
DebugLabelColor = render.MustHexColor("#FF9900")
|
||||||
DebugValueColor = render.MustHexColor("#00CCFF")
|
DebugValueColor = render.MustHexColor("#00CCFF")
|
||||||
|
|
9
pkg/balance/fonts.go
Normal file
9
pkg/balance/fonts.go
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
package balance
|
||||||
|
|
||||||
|
// Font filenames used as part of game configuration.
|
||||||
|
const (
|
||||||
|
// Main UI fonts (sans-serif and monospace)
|
||||||
|
SansSerifFont = "DejaVuSans.ttf"
|
||||||
|
MonospaceFont = "DejaVuSansMono.ttf"
|
||||||
|
SansBoldFont = "DejaVuSans-Bold.ttf"
|
||||||
|
)
|
|
@ -61,7 +61,7 @@ var (
|
||||||
|
|
||||||
// Default font filename selected for Text Tool in the editor.
|
// Default font filename selected for Text Tool in the editor.
|
||||||
// TODO: better centralize font filenames, here and in theme.go
|
// TODO: better centralize font filenames, here and in theme.go
|
||||||
TextToolDefaultFont = "DejaVuSans.ttf"
|
TextToolDefaultFont = SansSerifFont
|
||||||
|
|
||||||
// Interval for auto-save in the editor
|
// Interval for auto-save in the editor
|
||||||
AutoSaveInterval = 5 * time.Minute
|
AutoSaveInterval = 5 * time.Minute
|
||||||
|
|
|
@ -4,7 +4,7 @@ import "git.kirsle.net/go/render"
|
||||||
|
|
||||||
// Shell related variables.
|
// Shell related variables.
|
||||||
var (
|
var (
|
||||||
ShellFontFilename = "DejaVuSansMono.ttf"
|
ShellFontFilename = MonospaceFont
|
||||||
ShellBackgroundColor = render.RGBA(0, 20, 40, 200)
|
ShellBackgroundColor = render.RGBA(0, 20, 40, 200)
|
||||||
ShellForegroundColor = render.RGBA(0, 153, 255, 255)
|
ShellForegroundColor = render.RGBA(0, 153, 255, 255)
|
||||||
ShellPromptColor = render.White
|
ShellPromptColor = render.White
|
||||||
|
|
|
@ -23,7 +23,7 @@ var (
|
||||||
Shadow: render.Black,
|
Shadow: render.Black,
|
||||||
}
|
}
|
||||||
TitleScreenSubtitleFont = render.Text{
|
TitleScreenSubtitleFont = render.Text{
|
||||||
FontFilename: "DejaVuSans.ttf",
|
FontFilename: SansSerifFont,
|
||||||
Size: 18,
|
Size: 18,
|
||||||
Color: render.SkyBlue,
|
Color: render.SkyBlue,
|
||||||
Shadow: render.SkyBlue.Darken(128),
|
Shadow: render.SkyBlue.Darken(128),
|
||||||
|
@ -44,7 +44,7 @@ var (
|
||||||
Shadow: render.Black,
|
Shadow: render.Black,
|
||||||
}
|
}
|
||||||
LoadScreenSecondaryFont = render.Text{
|
LoadScreenSecondaryFont = render.Text{
|
||||||
FontFilename: "DejaVuSans.ttf",
|
FontFilename: SansSerifFont,
|
||||||
Size: 18,
|
Size: 18,
|
||||||
Color: render.SkyBlue,
|
Color: render.SkyBlue,
|
||||||
Shadow: render.SkyBlue.Darken(128),
|
Shadow: render.SkyBlue.Darken(128),
|
||||||
|
@ -54,7 +54,7 @@ var (
|
||||||
|
|
||||||
// Play Mode Touch UI Hints Font
|
// Play Mode Touch UI Hints Font
|
||||||
TouchHintsFont = render.Text{
|
TouchHintsFont = render.Text{
|
||||||
FontFilename: "DejaVuSans.ttf",
|
FontFilename: SansSerifFont,
|
||||||
Size: 14,
|
Size: 14,
|
||||||
Color: render.SkyBlue,
|
Color: render.SkyBlue,
|
||||||
Shadow: render.SkyBlue.Darken(128),
|
Shadow: render.SkyBlue.Darken(128),
|
||||||
|
@ -69,7 +69,7 @@ var (
|
||||||
OutlineColor: render.Black,
|
OutlineColor: render.Black,
|
||||||
}
|
}
|
||||||
TitleFont = render.Text{
|
TitleFont = render.Text{
|
||||||
FontFilename: "DejaVuSans-Bold.ttf",
|
FontFilename: SansBoldFont,
|
||||||
Size: 9,
|
Size: 9,
|
||||||
Padding: 4,
|
Padding: 4,
|
||||||
Color: render.White,
|
Color: render.White,
|
||||||
|
@ -99,7 +99,7 @@ var (
|
||||||
PadX: 4,
|
PadX: 4,
|
||||||
}
|
}
|
||||||
MenuFontBold = render.Text{
|
MenuFontBold = render.Text{
|
||||||
FontFilename: "DejaVuSans-Bold.ttf",
|
FontFilename: SansBoldFont,
|
||||||
Size: 12,
|
Size: 12,
|
||||||
PadX: 4,
|
PadX: 4,
|
||||||
}
|
}
|
||||||
|
@ -131,7 +131,7 @@ var (
|
||||||
// LabelFont is the font for strong labels in UI.
|
// LabelFont is the font for strong labels in UI.
|
||||||
LabelFont = render.Text{
|
LabelFont = render.Text{
|
||||||
Size: 12,
|
Size: 12,
|
||||||
FontFilename: "DejaVuSans-Bold.ttf",
|
FontFilename: SansBoldFont,
|
||||||
Padding: 4,
|
Padding: 4,
|
||||||
Color: render.Black,
|
Color: render.Black,
|
||||||
}
|
}
|
||||||
|
@ -148,7 +148,7 @@ var (
|
||||||
|
|
||||||
LargeLabelFont = render.Text{
|
LargeLabelFont = render.Text{
|
||||||
Size: 18,
|
Size: 18,
|
||||||
FontFilename: "DejaVuSans-Bold.ttf",
|
FontFilename: SansBoldFont,
|
||||||
Padding: 4,
|
Padding: 4,
|
||||||
Color: render.Black,
|
Color: render.Black,
|
||||||
}
|
}
|
||||||
|
@ -157,7 +157,7 @@ var (
|
||||||
SmallMonoFont = render.Text{
|
SmallMonoFont = render.Text{
|
||||||
Size: 14,
|
Size: 14,
|
||||||
PadX: 3,
|
PadX: 3,
|
||||||
FontFilename: "DejaVuSansMono.ttf",
|
FontFilename: MonospaceFont,
|
||||||
Color: render.Black,
|
Color: render.Black,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ var (
|
||||||
CodeLiteralFont = render.Text{
|
CodeLiteralFont = render.Text{
|
||||||
Size: 11,
|
Size: 11,
|
||||||
PadX: 3,
|
PadX: 3,
|
||||||
FontFilename: "DejaVuSansMono.ttf",
|
FontFilename: MonospaceFont,
|
||||||
Color: render.Magenta,
|
Color: render.Magenta,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,7 +185,7 @@ var (
|
||||||
LinkAnimSpeed uint64 = 30 // ticks
|
LinkAnimSpeed uint64 = 30 // ticks
|
||||||
|
|
||||||
PlayButtonFont = render.Text{
|
PlayButtonFont = render.Text{
|
||||||
FontFilename: "DejaVuSans-Bold.ttf",
|
FontFilename: SansBoldFont,
|
||||||
Size: 16,
|
Size: 16,
|
||||||
Padding: 4,
|
Padding: 4,
|
||||||
Color: render.RGBA(255, 255, 0, 255),
|
Color: render.RGBA(255, 255, 0, 255),
|
||||||
|
@ -194,7 +194,7 @@ var (
|
||||||
|
|
||||||
// In-game level timer font.
|
// In-game level timer font.
|
||||||
TimerFont = render.Text{
|
TimerFont = render.Text{
|
||||||
FontFilename: "DejaVuSansMono.ttf",
|
FontFilename: MonospaceFont,
|
||||||
Size: 16,
|
Size: 16,
|
||||||
Color: render.Cyan,
|
Color: render.Cyan,
|
||||||
Stroke: render.DarkCyan,
|
Stroke: render.DarkCyan,
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
package doodle
|
package doodle
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"git.kirsle.net/apps/doodle/pkg/balance"
|
"git.kirsle.net/apps/doodle/pkg/balance"
|
||||||
|
"git.kirsle.net/apps/doodle/pkg/modal/loadscreen"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IsDefaultPlayerCharacter checks whether the DefaultPlayerCharacter doodad has
|
// IsDefaultPlayerCharacter checks whether the DefaultPlayerCharacter doodad has
|
||||||
|
@ -146,6 +149,18 @@ func (c Command) cheatCommand(d *Doodle) bool {
|
||||||
d.FlashError("Use this cheat in Play Mode to toggle invincibility.")
|
d.FlashError("Use this cheat in Play Mode to toggle invincibility.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case balance.CheatDebugLoadScreen:
|
||||||
|
loadscreen.ShowWithProgress()
|
||||||
|
loadscreen.SetSubtitle("Loading: /dev/null", "Loadscreen testing.")
|
||||||
|
go func() {
|
||||||
|
var i float64
|
||||||
|
for i = 0; i < 100; i++ {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
loadscreen.SetProgress(i / 100)
|
||||||
|
}
|
||||||
|
loadscreen.Hide()
|
||||||
|
}()
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,8 +53,16 @@ func (u *EditorUI) SetupToolbar(d *Doodle) *ui.Frame {
|
||||||
// We can draw 2 buttons per row, but for very small screens
|
// We can draw 2 buttons per row, but for very small screens
|
||||||
// e.g. mobile in portrait orientation, draw 1 button per row.
|
// e.g. mobile in portrait orientation, draw 1 button per row.
|
||||||
buttonsPerRow = 1
|
buttonsPerRow = 1
|
||||||
if isHoz || d.width >= enum.ScreenWidthSmall {
|
if isHoz {
|
||||||
buttonsPerRow = 2
|
if d.width < enum.ScreenWidthSmall {
|
||||||
|
// Narrow screens
|
||||||
|
buttonsPerRow = 2
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if d.width >= enum.ScreenWidthSmall {
|
||||||
|
// Screen wider than 600px = can spare room for 2 buttons per row.
|
||||||
|
buttonsPerRow = 2
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute toolbar size to accommodate all buttons (+10 for borders/padding)
|
// Compute toolbar size to accommodate all buttons (+10 for borders/padding)
|
||||||
|
@ -229,10 +237,11 @@ func (u *EditorUI) SetupToolbar(d *Doodle) *ui.Frame {
|
||||||
})
|
})
|
||||||
u.Supervisor.Add(btn)
|
u.Supervisor.Add(btn)
|
||||||
|
|
||||||
ui.NewTooltip(btn, ui.Tooltip{
|
tt := ui.NewTooltip(btn, ui.Tooltip{
|
||||||
Text: button.Tooltip,
|
Text: button.Tooltip,
|
||||||
Edge: tooltipEdge,
|
Edge: tooltipEdge,
|
||||||
})
|
})
|
||||||
|
tt.Supervise(u.Supervisor)
|
||||||
|
|
||||||
btnRow.Pack(btn, btnPack)
|
btnRow.Pack(btn, btnPack)
|
||||||
}
|
}
|
||||||
|
@ -352,13 +361,22 @@ func (u *EditorUI) SetupToolbar(d *Doodle) *ui.Frame {
|
||||||
Text: button.Label,
|
Text: button.Label,
|
||||||
Font: balance.SmallMonoFont,
|
Font: balance.SmallMonoFont,
|
||||||
}))
|
}))
|
||||||
|
btn.SetBorderSize(1)
|
||||||
btn.Handle(ui.Click, func(ed ui.EventData) error {
|
btn.Handle(ui.Click, func(ed ui.EventData) error {
|
||||||
button.F()
|
button.F()
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
u.Supervisor.Add(btn)
|
u.Supervisor.Add(btn)
|
||||||
|
|
||||||
|
// Which side to pack on?
|
||||||
|
var side = ui.W
|
||||||
|
if !isHoz && buttonsPerRow == 1 {
|
||||||
|
// Vertical layout w/ narrow one-button-per-row, the +-
|
||||||
|
// buttons stick out so stack them vertically.
|
||||||
|
side = ui.S
|
||||||
|
}
|
||||||
sizeBtnFrame.Pack(btn, ui.Pack{
|
sizeBtnFrame.Pack(btn, ui.Pack{
|
||||||
Side: ui.W,
|
Side: side,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,7 @@ func (s *MainScene) Setup(d *Doodle) error {
|
||||||
s.updateButton = ui.NewButton("Update Button", ui.NewLabel(ui.Label{
|
s.updateButton = ui.NewButton("Update Button", ui.NewLabel(ui.Label{
|
||||||
Text: "An update is available!",
|
Text: "An update is available!",
|
||||||
Font: render.Text{
|
Font: render.Text{
|
||||||
FontFilename: "DejaVuSans-Bold.ttf",
|
FontFilename: balance.SansBoldFont,
|
||||||
Size: 16,
|
Size: 16,
|
||||||
Color: render.Blue,
|
Color: render.Blue,
|
||||||
Padding: 4,
|
Padding: 4,
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"git.kirsle.net/apps/doodle/pkg/log"
|
"git.kirsle.net/apps/doodle/pkg/log"
|
||||||
|
"git.kirsle.net/apps/doodle/pkg/shmem"
|
||||||
"git.kirsle.net/go/render"
|
"git.kirsle.net/go/render"
|
||||||
"git.kirsle.net/go/ui"
|
"git.kirsle.net/go/ui"
|
||||||
"git.kirsle.net/go/ui/style"
|
"git.kirsle.net/go/ui/style"
|
||||||
|
@ -21,6 +22,7 @@ const (
|
||||||
Checkbox
|
Checkbox
|
||||||
Radiobox
|
Radiobox
|
||||||
Selectbox
|
Selectbox
|
||||||
|
Color
|
||||||
)
|
)
|
||||||
|
|
||||||
// Form configuration.
|
// Form configuration.
|
||||||
|
@ -61,11 +63,12 @@ type Field struct {
|
||||||
Frame *ui.Frame
|
Frame *ui.Frame
|
||||||
|
|
||||||
// Variable bindings, the type may infer to be:
|
// Variable bindings, the type may infer to be:
|
||||||
BoolVariable *bool // Checkbox
|
BoolVariable *bool // Checkbox
|
||||||
TextVariable *string // Textbox
|
TextVariable *string // Textbox
|
||||||
IntVariable *int // Textbox
|
IntVariable *int // Textbox
|
||||||
Options []Option // Selectbox
|
Options []Option // Selectbox
|
||||||
SelectValue interface{} // Selectbox default choice
|
SelectValue interface{} // Selectbox default choice
|
||||||
|
Color *render.Color // Color
|
||||||
|
|
||||||
// Tooltip to add to a form control.
|
// Tooltip to add to a form control.
|
||||||
// Checkbox only for now.
|
// Checkbox only for now.
|
||||||
|
@ -181,6 +184,77 @@ func (form Form) Create(into *ui.Frame, fields []Field) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Color picker button.
|
||||||
|
if row.Type == Color && row.Color != nil {
|
||||||
|
btn := ui.NewButton("ColorPicker", ui.NewLabel(ui.Label{
|
||||||
|
Text: " ",
|
||||||
|
Font: row.Font,
|
||||||
|
}))
|
||||||
|
style := style.DefaultButton
|
||||||
|
style.Background = *row.Color
|
||||||
|
style.HoverBackground = style.Background.Lighten(20)
|
||||||
|
btn.SetStyle(&style)
|
||||||
|
|
||||||
|
form.Supervisor.Add(btn)
|
||||||
|
frame.Pack(btn, ui.Pack{
|
||||||
|
Side: ui.W,
|
||||||
|
FillX: true,
|
||||||
|
Expand: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
btn.Handle(ui.Click, func(ed ui.EventData) error {
|
||||||
|
// Open a ColorPicker widget.
|
||||||
|
picker, err := ui.NewColorPicker(ui.ColorPicker{
|
||||||
|
Title: "Select a color",
|
||||||
|
Supervisor: form.Supervisor,
|
||||||
|
Engine: form.Engine,
|
||||||
|
Color: *row.Color,
|
||||||
|
OnManualInput: func(callback func(render.Color)) {
|
||||||
|
// Prompt the user to enter a hex color using the developer shell.
|
||||||
|
shmem.Prompt("New color in hex notation: ", func(answer string) {
|
||||||
|
if answer != "" {
|
||||||
|
// XXX: pure white renders as invisible, fudge it a bit.
|
||||||
|
if answer == "FFFFFF" {
|
||||||
|
answer = "FFFFFE"
|
||||||
|
}
|
||||||
|
|
||||||
|
color, err := render.HexColor(answer)
|
||||||
|
if err != nil {
|
||||||
|
shmem.Flash("Error with that color code: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reconfigure the button now.
|
||||||
|
style.Background = color
|
||||||
|
style.HoverBackground = style.Background.Lighten(20)
|
||||||
|
|
||||||
|
callback(color)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Couldn't open ColorPicker: %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
picker.Then(func(color render.Color) {
|
||||||
|
*row.Color = color
|
||||||
|
style.Background = color
|
||||||
|
style.HoverBackground = style.Background.Lighten(20)
|
||||||
|
|
||||||
|
// call onClick to save change to disk now
|
||||||
|
if row.OnClick != nil {
|
||||||
|
row.OnClick()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
picker.Center(shmem.CurrentRenderEngine.WindowSize())
|
||||||
|
picker.Show()
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Buttons and Text fields (for now).
|
// Buttons and Text fields (for now).
|
||||||
if row.Type == Button || row.Type == Textbox {
|
if row.Type == Button || row.Type == Textbox {
|
||||||
btn := ui.NewButton("Button", ui.NewLabel(ui.Label{
|
btn := ui.NewButton("Button", ui.NewLabel(ui.Label{
|
||||||
|
@ -198,7 +272,8 @@ func (form Form) Create(into *ui.Frame, fields []Field) {
|
||||||
|
|
||||||
// Tooltip? TODO - make nicer.
|
// Tooltip? TODO - make nicer.
|
||||||
if row.Tooltip.Text != "" || row.Tooltip.TextVariable != nil {
|
if row.Tooltip.Text != "" || row.Tooltip.TextVariable != nil {
|
||||||
ui.NewTooltip(btn, row.Tooltip)
|
tt := ui.NewTooltip(btn, row.Tooltip)
|
||||||
|
tt.Supervise(form.Supervisor)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handlers
|
// Handlers
|
||||||
|
@ -224,7 +299,8 @@ func (form Form) Create(into *ui.Frame, fields []Field) {
|
||||||
|
|
||||||
// Tooltip? TODO - make nicer.
|
// Tooltip? TODO - make nicer.
|
||||||
if row.Tooltip.Text != "" || row.Tooltip.TextVariable != nil {
|
if row.Tooltip.Text != "" || row.Tooltip.TextVariable != nil {
|
||||||
ui.NewTooltip(cb, row.Tooltip)
|
tt := ui.NewTooltip(cb, row.Tooltip)
|
||||||
|
tt.Supervise(form.Supervisor)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handlers
|
// Handlers
|
||||||
|
|
|
@ -244,10 +244,11 @@ func makeDoodadTab(config DoodadDropper, frame *ui.Frame, size render.Rect, cate
|
||||||
})
|
})
|
||||||
|
|
||||||
// Tooltip hover to show the doodad's name.
|
// Tooltip hover to show the doodad's name.
|
||||||
ui.NewTooltip(btn, ui.Tooltip{
|
tt := ui.NewTooltip(btn, ui.Tooltip{
|
||||||
Text: doodad.Title,
|
Text: doodad.Title,
|
||||||
Edge: ui.Top,
|
Edge: ui.Top,
|
||||||
})
|
})
|
||||||
|
tt.Supervise(config.Supervisor)
|
||||||
|
|
||||||
// Begin the drag event to grab this Doodad.
|
// Begin the drag event to grab this Doodad.
|
||||||
// NOTE: The drag target is the EditorUI.Canvas in
|
// NOTE: The drag target is the EditorUI.Canvas in
|
||||||
|
|
|
@ -1,20 +1,17 @@
|
||||||
package windows
|
package windows
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.kirsle.net/apps/doodle/pkg/balance"
|
"git.kirsle.net/apps/doodle/pkg/balance"
|
||||||
"git.kirsle.net/apps/doodle/pkg/gamepad"
|
"git.kirsle.net/apps/doodle/pkg/gamepad"
|
||||||
"git.kirsle.net/apps/doodle/pkg/log"
|
"git.kirsle.net/apps/doodle/pkg/log"
|
||||||
"git.kirsle.net/apps/doodle/pkg/native"
|
"git.kirsle.net/apps/doodle/pkg/native"
|
||||||
"git.kirsle.net/apps/doodle/pkg/shmem"
|
|
||||||
magicform "git.kirsle.net/apps/doodle/pkg/uix/magic-form"
|
magicform "git.kirsle.net/apps/doodle/pkg/uix/magic-form"
|
||||||
"git.kirsle.net/apps/doodle/pkg/usercfg"
|
"git.kirsle.net/apps/doodle/pkg/usercfg"
|
||||||
"git.kirsle.net/apps/doodle/pkg/userdir"
|
"git.kirsle.net/apps/doodle/pkg/userdir"
|
||||||
"git.kirsle.net/go/render"
|
"git.kirsle.net/go/render"
|
||||||
"git.kirsle.net/go/ui"
|
"git.kirsle.net/go/ui"
|
||||||
"git.kirsle.net/go/ui/style"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Settings window.
|
// Settings window.
|
||||||
|
@ -61,7 +58,7 @@ func MakeSettingsWindow(windowWidth, windowHeight int, cfg Settings) *ui.Window
|
||||||
func NewSettingsWindow(cfg Settings) *ui.Window {
|
func NewSettingsWindow(cfg Settings) *ui.Window {
|
||||||
var (
|
var (
|
||||||
Width = 400
|
Width = 400
|
||||||
Height = 400
|
Height = 360
|
||||||
)
|
)
|
||||||
|
|
||||||
window := ui.NewWindow("Settings")
|
window := ui.NewWindow("Settings")
|
||||||
|
@ -111,305 +108,98 @@ func (c Settings) makeOptionsTab(tabFrame *ui.TabFrame, Width, Height int) *ui.F
|
||||||
|
|
||||||
// Common click handler for all settings,
|
// Common click handler for all settings,
|
||||||
// so we can write the updated info to disk.
|
// so we can write the updated info to disk.
|
||||||
onClick := func(ed ui.EventData) error {
|
onClick := func() {
|
||||||
saveGameSettings()
|
saveGameSettings()
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var inputBoxWidth = 120
|
// The CrosshairSize is ideally a 0-100 (percent) how big the editor
|
||||||
rows := []struct {
|
// crosshair is, but options now are only 0% or 100% so it presents
|
||||||
Header string
|
// this as a checkbox for now.
|
||||||
Text string
|
var crosshairEnabled = *c.CrosshairSize > 0
|
||||||
Boolean *bool
|
|
||||||
Integer *int
|
form := magicform.Form{
|
||||||
TextVariable *string
|
Supervisor: c.Supervisor,
|
||||||
Color *render.Color
|
Engine: c.Engine,
|
||||||
PadY int
|
Vertical: true,
|
||||||
PadX int
|
LabelWidth: 150,
|
||||||
name string // for special cases
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
Text: "Notice: all settings are temporary and controls are not editable.",
|
|
||||||
PadY: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Header: "Game Options",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Boolean: c.HorizontalToolbars,
|
|
||||||
Text: "Editor: Horizontal instead of vertical toolbars",
|
|
||||||
PadX: 4,
|
|
||||||
name: "toolbars",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Boolean: c.HideTouchHints,
|
|
||||||
Text: "Hide touchscreen control hints during Play Mode",
|
|
||||||
PadX: 4,
|
|
||||||
name: "toolbars",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Boolean: c.DisableAutosave,
|
|
||||||
Text: "Disable auto-save in the Editor",
|
|
||||||
PadX: 4,
|
|
||||||
name: "autosave",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Integer: c.CrosshairSize,
|
|
||||||
Text: "Editor: Crosshair size (0 to disable):",
|
|
||||||
PadX: 4,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Color: c.CrosshairColor,
|
|
||||||
Text: "Editor: Crosshair color:",
|
|
||||||
PadX: 4,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Header: "Debug Options (temporary)",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Boolean: c.DebugOverlay,
|
|
||||||
Text: "Show debug text overlay (F3)",
|
|
||||||
PadX: 4,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Boolean: c.DebugCollision,
|
|
||||||
Text: "Show collision hitboxes (F4)",
|
|
||||||
PadX: 4,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Header: "My Custom Content",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Text: "Levels and doodads you create in-game are placed in your\n" +
|
|
||||||
"Profile Directory, which you can access below:",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
for _, row := range rows {
|
form.Create(tab, []magicform.Field{
|
||||||
row := row
|
|
||||||
frame := ui.NewFrame("Frame")
|
|
||||||
tab.Pack(frame, ui.Pack{
|
|
||||||
Side: ui.N,
|
|
||||||
FillX: true,
|
|
||||||
PadY: row.PadY,
|
|
||||||
})
|
|
||||||
|
|
||||||
// Headers get their own row to themselves.
|
|
||||||
if row.Header != "" {
|
|
||||||
label := ui.NewLabel(ui.Label{
|
|
||||||
Text: row.Header,
|
|
||||||
Font: balance.LabelFont,
|
|
||||||
})
|
|
||||||
frame.Pack(label, ui.Pack{
|
|
||||||
Side: ui.W,
|
|
||||||
PadX: row.PadX,
|
|
||||||
})
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checkboxes get their own row.
|
|
||||||
if row.Boolean != nil {
|
|
||||||
cb := ui.NewCheckbox(row.Text, row.Boolean, ui.NewLabel(ui.Label{
|
|
||||||
Text: row.Text,
|
|
||||||
Font: balance.UIFont,
|
|
||||||
}))
|
|
||||||
cb.Handle(ui.Click, onClick)
|
|
||||||
cb.Supervise(c.Supervisor)
|
|
||||||
|
|
||||||
// Add warning to the toolbars option if the EditMode is currently active.
|
|
||||||
if row.name == "toolbars" && c.SceneName == "Edit" {
|
|
||||||
ui.NewTooltip(cb, ui.Tooltip{
|
|
||||||
Text: "Note: reload your level after changing this option.\n" +
|
|
||||||
"Playtesting and returning will do.",
|
|
||||||
Edge: ui.Top,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
frame.Pack(cb, ui.Pack{
|
|
||||||
Side: ui.W,
|
|
||||||
PadX: row.PadX,
|
|
||||||
})
|
|
||||||
continue
|
|
||||||
} else {
|
|
||||||
// Reserve indented space where the checkbox would have gone.
|
|
||||||
spacer := ui.NewFrame("Spacer")
|
|
||||||
spacer.Resize(render.NewRect(9, 9)) // TODO: ugly UI hack ;)
|
|
||||||
frame.Pack(spacer, ui.Pack{
|
|
||||||
Side: ui.W,
|
|
||||||
PadX: row.PadX,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Any leftover Text gets packed to the left.
|
|
||||||
if row.Text != "" {
|
|
||||||
tf := ui.NewFrame("TextFrame")
|
|
||||||
label := ui.NewLabel(ui.Label{
|
|
||||||
Text: row.Text,
|
|
||||||
Font: balance.UIFont,
|
|
||||||
})
|
|
||||||
tf.Pack(label, ui.Pack{
|
|
||||||
Side: ui.W,
|
|
||||||
})
|
|
||||||
frame.Pack(tf, ui.Pack{
|
|
||||||
Side: ui.W,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Int variables draw as a button to prompt for new value.
|
|
||||||
// In future: TextVariable works here too.
|
|
||||||
if row.Integer != nil {
|
|
||||||
varButton := ui.NewButton("VarButton", ui.NewLabel(ui.Label{
|
|
||||||
IntVariable: row.Integer,
|
|
||||||
Font: ui.MenuFont,
|
|
||||||
}))
|
|
||||||
varButton.Handle(ui.Click, func(ed ui.EventData) error {
|
|
||||||
shmem.Prompt(row.Text+" ", func(answer string) {
|
|
||||||
if answer == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
a, err := strconv.Atoi(answer)
|
|
||||||
if err != nil {
|
|
||||||
shmem.FlashError(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if a < 0 {
|
|
||||||
a = 0
|
|
||||||
} else if a > 100 {
|
|
||||||
a = 100
|
|
||||||
}
|
|
||||||
|
|
||||||
*row.Integer = a
|
|
||||||
shmem.Flash("Crosshair size set to %d%% (WIP)", a)
|
|
||||||
|
|
||||||
// call onClick to save change to disk now
|
|
||||||
onClick(ed)
|
|
||||||
})
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
varButton.Compute(c.Engine)
|
|
||||||
varButton.Resize(render.Rect{
|
|
||||||
W: inputBoxWidth,
|
|
||||||
H: varButton.Size().H,
|
|
||||||
})
|
|
||||||
|
|
||||||
c.Supervisor.Add(varButton)
|
|
||||||
frame.Pack(varButton, ui.Pack{
|
|
||||||
Side: ui.E,
|
|
||||||
PadX: row.PadX,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Color picker button.
|
|
||||||
if row.Color != nil {
|
|
||||||
btn := ui.NewButton("ColorBtn", ui.NewFrame(""))
|
|
||||||
style := style.DefaultButton
|
|
||||||
style.Background = *row.Color
|
|
||||||
style.HoverBackground = style.Background.Lighten(20)
|
|
||||||
btn.SetStyle(&style)
|
|
||||||
btn.Handle(ui.Click, func(ed ui.EventData) error {
|
|
||||||
// Open a ColorPicker widget.
|
|
||||||
picker, err := ui.NewColorPicker(ui.ColorPicker{
|
|
||||||
Title: "Select a color",
|
|
||||||
Supervisor: c.Supervisor,
|
|
||||||
Engine: c.Engine,
|
|
||||||
Color: *row.Color,
|
|
||||||
OnManualInput: func(callback func(render.Color)) {
|
|
||||||
// Prompt the user to enter a hex color using the developer shell.
|
|
||||||
shmem.Prompt("New color in hex notation: ", func(answer string) {
|
|
||||||
if answer != "" {
|
|
||||||
// XXX: pure white renders as invisible, fudge it a bit.
|
|
||||||
if answer == "FFFFFF" {
|
|
||||||
answer = "FFFFFE"
|
|
||||||
}
|
|
||||||
|
|
||||||
color, err := render.HexColor(answer)
|
|
||||||
if err != nil {
|
|
||||||
shmem.Flash("Error with that color code: %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
callback(color)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Couldn't open ColorPicker: %s", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
picker.Then(func(color render.Color) {
|
|
||||||
*row.Color = color
|
|
||||||
style.Background = color
|
|
||||||
style.HoverBackground = style.Background.Lighten(20)
|
|
||||||
|
|
||||||
// call onClick to save change to disk now
|
|
||||||
onClick(ed)
|
|
||||||
})
|
|
||||||
|
|
||||||
picker.Center(shmem.CurrentRenderEngine.WindowSize())
|
|
||||||
picker.Show()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
btn.Compute(c.Engine)
|
|
||||||
btn.Resize(render.Rect{
|
|
||||||
W: inputBoxWidth,
|
|
||||||
H: 20, // TODO
|
|
||||||
})
|
|
||||||
|
|
||||||
c.Supervisor.Add(btn)
|
|
||||||
frame.Pack(btn, ui.Pack{
|
|
||||||
Side: ui.E,
|
|
||||||
PadX: row.PadX,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Button toolbar.
|
|
||||||
btnFrame := ui.NewFrame("Button Frame")
|
|
||||||
tab.Pack(btnFrame, ui.Pack{
|
|
||||||
Side: ui.N,
|
|
||||||
FillX: true,
|
|
||||||
PadY: 4,
|
|
||||||
})
|
|
||||||
for _, button := range []struct {
|
|
||||||
Label string
|
|
||||||
Fn func()
|
|
||||||
Style *style.Button
|
|
||||||
}{
|
|
||||||
{
|
{
|
||||||
Label: "Open profile directory",
|
Label: "Game Options",
|
||||||
Fn: func() {
|
Font: balance.LabelFont,
|
||||||
path := strings.ReplaceAll(userdir.ProfileDirectory, "\\", "/")
|
},
|
||||||
if path[0] != '/' {
|
{
|
||||||
path = "/" + path
|
Label: "Hide touchscreen control hints during Play Mode",
|
||||||
}
|
Font: balance.UIFont,
|
||||||
native.OpenURL("file://" + path)
|
BoolVariable: c.HideTouchHints,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Label: "Level & Doodad Editor",
|
||||||
|
Font: balance.LabelFont,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Label: "Horizontal instead of vertical toolbars",
|
||||||
|
Font: balance.UIFont,
|
||||||
|
BoolVariable: c.HorizontalToolbars,
|
||||||
|
Tooltip: ui.Tooltip{
|
||||||
|
Text: "Note: reload your level after changing this option.\n" +
|
||||||
|
"Playtesting and returning will do.",
|
||||||
|
Edge: ui.Top,
|
||||||
},
|
},
|
||||||
Style: &balance.ButtonPrimary,
|
|
||||||
},
|
},
|
||||||
} {
|
{
|
||||||
btn := ui.NewButton(button.Label, ui.NewLabel(ui.Label{
|
Label: "Disable auto-save in the Editor",
|
||||||
Text: button.Label,
|
Font: balance.UIFont,
|
||||||
|
BoolVariable: c.DisableAutosave,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Label: "Draw a crosshair at the mouse cursor.",
|
||||||
|
Font: balance.UIFont,
|
||||||
|
BoolVariable: &crosshairEnabled,
|
||||||
|
OnClick: func() {
|
||||||
|
if crosshairEnabled {
|
||||||
|
*c.CrosshairSize = 100
|
||||||
|
} else {
|
||||||
|
*c.CrosshairSize = 0
|
||||||
|
}
|
||||||
|
onClick()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: magicform.Color,
|
||||||
|
Label: "Crosshair color:",
|
||||||
|
Font: balance.UIFont,
|
||||||
|
Color: c.CrosshairColor,
|
||||||
|
OnClick: func() {
|
||||||
|
onClick()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Label: "My Custom Content",
|
||||||
|
Font: balance.LabelFont,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Label: "Levels and doodads you create in-game are placed in your\n" +
|
||||||
|
"Profile Directory, which you can access below:",
|
||||||
Font: balance.UIFont,
|
Font: balance.UIFont,
|
||||||
}))
|
},
|
||||||
if button.Style != nil {
|
{
|
||||||
btn.SetStyle(button.Style)
|
Buttons: []magicform.Field{
|
||||||
}
|
{
|
||||||
btn.Handle(ui.Click, func(ed ui.EventData) error {
|
Label: "Open profile directory",
|
||||||
button.Fn()
|
Font: balance.UIFont,
|
||||||
return nil
|
ButtonStyle: &balance.ButtonPrimary,
|
||||||
})
|
OnClick: func() {
|
||||||
c.Supervisor.Add(btn)
|
path := strings.ReplaceAll(userdir.ProfileDirectory, "\\", "/")
|
||||||
btnFrame.Pack(btn, ui.Pack{
|
if path[0] != '/' {
|
||||||
Side: ui.W,
|
path = "/" + path
|
||||||
Expand: true,
|
}
|
||||||
})
|
native.OpenURL("file://" + path)
|
||||||
}
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
return tab
|
return tab
|
||||||
}
|
}
|
||||||
|
@ -575,7 +365,7 @@ func (c Settings) makeControlsTab(tabFrame *ui.TabFrame, Width, Height int) *ui.
|
||||||
frame.Pack(curFrame, ui.Pack{
|
frame.Pack(curFrame, ui.Pack{
|
||||||
Side: ui.N,
|
Side: ui.N,
|
||||||
FillX: true,
|
FillX: true,
|
||||||
PadY: 2,
|
PadY: 1,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -743,14 +533,13 @@ func (c Settings) makeControllerTab(tabFrame *ui.TabFrame, Width, Height int) *u
|
||||||
}
|
}
|
||||||
form.Create(tab, []magicform.Field{
|
form.Create(tab, []magicform.Field{
|
||||||
{
|
{
|
||||||
Label: "About",
|
Label: "Play with an Xbox or Nintendo controller!",
|
||||||
Font: balance.LabelFont,
|
Font: balance.LabelFont,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Label: "Play Sketchy Maze with an Xbox or Nintendo controller!\n\n" +
|
Label: "If you have a Nintendo-style controller (your A button is on\n" +
|
||||||
"Full customization options aren't here yet, but you can\n" +
|
"the right and B button on bottom), pick 'N Style' to reverse\n" +
|
||||||
"choose between the 'X Style' or 'N Style' profile below.\n" +
|
"the A/B and X/Y buttons.",
|
||||||
"'N Style' will swap the A/B and X/Y buttons.",
|
|
||||||
Font: balance.UIFont,
|
Font: balance.UIFont,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -776,7 +565,7 @@ func (c Settings) makeControllerTab(tabFrame *ui.TabFrame, Width, Height int) *u
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Label: "\nThe gamepad controls vary between two modes:",
|
Label: "The gamepad controls vary between two modes:",
|
||||||
Font: balance.UIFont,
|
Font: balance.UIFont,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue
Block a user