From 44122d41308eeee6891883944a43187a5ea1b8bf Mon Sep 17 00:00:00 2001 From: Noah Petherbridge Date: Sat, 5 Mar 2022 22:44:54 -0800 Subject: [PATCH] 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` --- pkg/balance/cheats.go | 1 + pkg/balance/debug.go | 2 +- pkg/balance/fonts.go | 9 + pkg/balance/numbers.go | 2 +- pkg/balance/shell.go | 2 +- pkg/balance/theme.go | 22 +- pkg/cheats.go | 15 ++ pkg/editor_ui_toolbar.go | 26 +- pkg/main_scene.go | 2 +- pkg/uix/magic-form/magic_form.go | 90 ++++++- pkg/windows/doodad_dropper.go | 3 +- pkg/windows/settings.go | 393 +++++++------------------------ 12 files changed, 238 insertions(+), 329 deletions(-) create mode 100644 pkg/balance/fonts.go diff --git a/pkg/balance/cheats.go b/pkg/balance/cheats.go index 830a41b..ca7be9a 100644 --- a/pkg/balance/cheats.go +++ b/pkg/balance/cheats.go @@ -31,4 +31,5 @@ var ( CheatPlayAsThief = "play as thief" CheatPlayAsAnvil = "megaton weight" CheatGodMode = "god mode" + CheatDebugLoadScreen = "test load screen" ) diff --git a/pkg/balance/debug.go b/pkg/balance/debug.go index 3a3d85e..0a964f7 100644 --- a/pkg/balance/debug.go +++ b/pkg/balance/debug.go @@ -16,7 +16,7 @@ var ( ***************/ // Debug overlay (FPS etc.) settings. - DebugFontFilename = "DejaVuSans-Bold.ttf" + DebugFontFilename = SansBoldFont DebugFontSize = 16 DebugLabelColor = render.MustHexColor("#FF9900") DebugValueColor = render.MustHexColor("#00CCFF") diff --git a/pkg/balance/fonts.go b/pkg/balance/fonts.go new file mode 100644 index 0000000..b424266 --- /dev/null +++ b/pkg/balance/fonts.go @@ -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" +) diff --git a/pkg/balance/numbers.go b/pkg/balance/numbers.go index bd2c649..25c441a 100644 --- a/pkg/balance/numbers.go +++ b/pkg/balance/numbers.go @@ -61,7 +61,7 @@ var ( // Default font filename selected for Text Tool in the editor. // TODO: better centralize font filenames, here and in theme.go - TextToolDefaultFont = "DejaVuSans.ttf" + TextToolDefaultFont = SansSerifFont // Interval for auto-save in the editor AutoSaveInterval = 5 * time.Minute diff --git a/pkg/balance/shell.go b/pkg/balance/shell.go index 1e9b3b4..f195441 100644 --- a/pkg/balance/shell.go +++ b/pkg/balance/shell.go @@ -4,7 +4,7 @@ import "git.kirsle.net/go/render" // Shell related variables. var ( - ShellFontFilename = "DejaVuSansMono.ttf" + ShellFontFilename = MonospaceFont ShellBackgroundColor = render.RGBA(0, 20, 40, 200) ShellForegroundColor = render.RGBA(0, 153, 255, 255) ShellPromptColor = render.White diff --git a/pkg/balance/theme.go b/pkg/balance/theme.go index 91b6bc7..c8f4384 100644 --- a/pkg/balance/theme.go +++ b/pkg/balance/theme.go @@ -23,7 +23,7 @@ var ( Shadow: render.Black, } TitleScreenSubtitleFont = render.Text{ - FontFilename: "DejaVuSans.ttf", + FontFilename: SansSerifFont, Size: 18, Color: render.SkyBlue, Shadow: render.SkyBlue.Darken(128), @@ -44,7 +44,7 @@ var ( Shadow: render.Black, } LoadScreenSecondaryFont = render.Text{ - FontFilename: "DejaVuSans.ttf", + FontFilename: SansSerifFont, Size: 18, Color: render.SkyBlue, Shadow: render.SkyBlue.Darken(128), @@ -54,7 +54,7 @@ var ( // Play Mode Touch UI Hints Font TouchHintsFont = render.Text{ - FontFilename: "DejaVuSans.ttf", + FontFilename: SansSerifFont, Size: 14, Color: render.SkyBlue, Shadow: render.SkyBlue.Darken(128), @@ -69,7 +69,7 @@ var ( OutlineColor: render.Black, } TitleFont = render.Text{ - FontFilename: "DejaVuSans-Bold.ttf", + FontFilename: SansBoldFont, Size: 9, Padding: 4, Color: render.White, @@ -99,7 +99,7 @@ var ( PadX: 4, } MenuFontBold = render.Text{ - FontFilename: "DejaVuSans-Bold.ttf", + FontFilename: SansBoldFont, Size: 12, PadX: 4, } @@ -131,7 +131,7 @@ var ( // LabelFont is the font for strong labels in UI. LabelFont = render.Text{ Size: 12, - FontFilename: "DejaVuSans-Bold.ttf", + FontFilename: SansBoldFont, Padding: 4, Color: render.Black, } @@ -148,7 +148,7 @@ var ( LargeLabelFont = render.Text{ Size: 18, - FontFilename: "DejaVuSans-Bold.ttf", + FontFilename: SansBoldFont, Padding: 4, Color: render.Black, } @@ -157,7 +157,7 @@ var ( SmallMonoFont = render.Text{ Size: 14, PadX: 3, - FontFilename: "DejaVuSansMono.ttf", + FontFilename: MonospaceFont, Color: render.Black, } @@ -165,7 +165,7 @@ var ( CodeLiteralFont = render.Text{ Size: 11, PadX: 3, - FontFilename: "DejaVuSansMono.ttf", + FontFilename: MonospaceFont, Color: render.Magenta, } @@ -185,7 +185,7 @@ var ( LinkAnimSpeed uint64 = 30 // ticks PlayButtonFont = render.Text{ - FontFilename: "DejaVuSans-Bold.ttf", + FontFilename: SansBoldFont, Size: 16, Padding: 4, Color: render.RGBA(255, 255, 0, 255), @@ -194,7 +194,7 @@ var ( // In-game level timer font. TimerFont = render.Text{ - FontFilename: "DejaVuSansMono.ttf", + FontFilename: MonospaceFont, Size: 16, Color: render.Cyan, Stroke: render.DarkCyan, diff --git a/pkg/cheats.go b/pkg/cheats.go index 789d6ff..f00eff0 100644 --- a/pkg/cheats.go +++ b/pkg/cheats.go @@ -1,7 +1,10 @@ package doodle import ( + "time" + "git.kirsle.net/apps/doodle/pkg/balance" + "git.kirsle.net/apps/doodle/pkg/modal/loadscreen" ) // 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.") } + 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: return false } diff --git a/pkg/editor_ui_toolbar.go b/pkg/editor_ui_toolbar.go index f7dce0c..65e69ac 100644 --- a/pkg/editor_ui_toolbar.go +++ b/pkg/editor_ui_toolbar.go @@ -53,8 +53,16 @@ func (u *EditorUI) SetupToolbar(d *Doodle) *ui.Frame { // We can draw 2 buttons per row, but for very small screens // e.g. mobile in portrait orientation, draw 1 button per row. buttonsPerRow = 1 - if isHoz || d.width >= enum.ScreenWidthSmall { - buttonsPerRow = 2 + if isHoz { + 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) @@ -229,10 +237,11 @@ func (u *EditorUI) SetupToolbar(d *Doodle) *ui.Frame { }) u.Supervisor.Add(btn) - ui.NewTooltip(btn, ui.Tooltip{ + tt := ui.NewTooltip(btn, ui.Tooltip{ Text: button.Tooltip, Edge: tooltipEdge, }) + tt.Supervise(u.Supervisor) btnRow.Pack(btn, btnPack) } @@ -352,13 +361,22 @@ func (u *EditorUI) SetupToolbar(d *Doodle) *ui.Frame { Text: button.Label, Font: balance.SmallMonoFont, })) + btn.SetBorderSize(1) btn.Handle(ui.Click, func(ed ui.EventData) error { button.F() return nil }) 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{ - Side: ui.W, + Side: side, }) } } diff --git a/pkg/main_scene.go b/pkg/main_scene.go index 6c40405..b9d9ca4 100644 --- a/pkg/main_scene.go +++ b/pkg/main_scene.go @@ -113,7 +113,7 @@ func (s *MainScene) Setup(d *Doodle) error { s.updateButton = ui.NewButton("Update Button", ui.NewLabel(ui.Label{ Text: "An update is available!", Font: render.Text{ - FontFilename: "DejaVuSans-Bold.ttf", + FontFilename: balance.SansBoldFont, Size: 16, Color: render.Blue, Padding: 4, diff --git a/pkg/uix/magic-form/magic_form.go b/pkg/uix/magic-form/magic_form.go index 74c54d0..2aced85 100644 --- a/pkg/uix/magic-form/magic_form.go +++ b/pkg/uix/magic-form/magic_form.go @@ -5,6 +5,7 @@ import ( "fmt" "git.kirsle.net/apps/doodle/pkg/log" + "git.kirsle.net/apps/doodle/pkg/shmem" "git.kirsle.net/go/render" "git.kirsle.net/go/ui" "git.kirsle.net/go/ui/style" @@ -21,6 +22,7 @@ const ( Checkbox Radiobox Selectbox + Color ) // Form configuration. @@ -61,11 +63,12 @@ type Field struct { Frame *ui.Frame // Variable bindings, the type may infer to be: - BoolVariable *bool // Checkbox - TextVariable *string // Textbox - IntVariable *int // Textbox - Options []Option // Selectbox - SelectValue interface{} // Selectbox default choice + BoolVariable *bool // Checkbox + TextVariable *string // Textbox + IntVariable *int // Textbox + Options []Option // Selectbox + SelectValue interface{} // Selectbox default choice + Color *render.Color // Color // Tooltip to add to a form control. // 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). if row.Type == Button || row.Type == Textbox { 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. if row.Tooltip.Text != "" || row.Tooltip.TextVariable != nil { - ui.NewTooltip(btn, row.Tooltip) + tt := ui.NewTooltip(btn, row.Tooltip) + tt.Supervise(form.Supervisor) } // Handlers @@ -224,7 +299,8 @@ func (form Form) Create(into *ui.Frame, fields []Field) { // Tooltip? TODO - make nicer. if row.Tooltip.Text != "" || row.Tooltip.TextVariable != nil { - ui.NewTooltip(cb, row.Tooltip) + tt := ui.NewTooltip(cb, row.Tooltip) + tt.Supervise(form.Supervisor) } // Handlers diff --git a/pkg/windows/doodad_dropper.go b/pkg/windows/doodad_dropper.go index 530db4a..ac141a6 100644 --- a/pkg/windows/doodad_dropper.go +++ b/pkg/windows/doodad_dropper.go @@ -244,10 +244,11 @@ func makeDoodadTab(config DoodadDropper, frame *ui.Frame, size render.Rect, cate }) // Tooltip hover to show the doodad's name. - ui.NewTooltip(btn, ui.Tooltip{ + tt := ui.NewTooltip(btn, ui.Tooltip{ Text: doodad.Title, Edge: ui.Top, }) + tt.Supervise(config.Supervisor) // Begin the drag event to grab this Doodad. // NOTE: The drag target is the EditorUI.Canvas in diff --git a/pkg/windows/settings.go b/pkg/windows/settings.go index ee7339d..4b3df25 100644 --- a/pkg/windows/settings.go +++ b/pkg/windows/settings.go @@ -1,20 +1,17 @@ package windows import ( - "strconv" "strings" "git.kirsle.net/apps/doodle/pkg/balance" "git.kirsle.net/apps/doodle/pkg/gamepad" "git.kirsle.net/apps/doodle/pkg/log" "git.kirsle.net/apps/doodle/pkg/native" - "git.kirsle.net/apps/doodle/pkg/shmem" magicform "git.kirsle.net/apps/doodle/pkg/uix/magic-form" "git.kirsle.net/apps/doodle/pkg/usercfg" "git.kirsle.net/apps/doodle/pkg/userdir" "git.kirsle.net/go/render" "git.kirsle.net/go/ui" - "git.kirsle.net/go/ui/style" ) // Settings window. @@ -61,7 +58,7 @@ func MakeSettingsWindow(windowWidth, windowHeight int, cfg Settings) *ui.Window func NewSettingsWindow(cfg Settings) *ui.Window { var ( Width = 400 - Height = 400 + Height = 360 ) 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, // so we can write the updated info to disk. - onClick := func(ed ui.EventData) error { + onClick := func() { saveGameSettings() - return nil } - var inputBoxWidth = 120 - rows := []struct { - Header string - Text string - Boolean *bool - Integer *int - TextVariable *string - Color *render.Color - PadY int - PadX int - 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:", - }, + // The CrosshairSize is ideally a 0-100 (percent) how big the editor + // crosshair is, but options now are only 0% or 100% so it presents + // this as a checkbox for now. + var crosshairEnabled = *c.CrosshairSize > 0 + + form := magicform.Form{ + Supervisor: c.Supervisor, + Engine: c.Engine, + Vertical: true, + LabelWidth: 150, } - for _, row := range rows { - 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 - }{ + form.Create(tab, []magicform.Field{ { - Label: "Open profile directory", - Fn: func() { - path := strings.ReplaceAll(userdir.ProfileDirectory, "\\", "/") - if path[0] != '/' { - path = "/" + path - } - native.OpenURL("file://" + path) + Label: "Game Options", + Font: balance.LabelFont, + }, + { + Label: "Hide touchscreen control hints during Play Mode", + Font: balance.UIFont, + 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{ - Text: button.Label, + { + Label: "Disable auto-save in the Editor", + 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, - })) - if button.Style != nil { - btn.SetStyle(button.Style) - } - btn.Handle(ui.Click, func(ed ui.EventData) error { - button.Fn() - return nil - }) - c.Supervisor.Add(btn) - btnFrame.Pack(btn, ui.Pack{ - Side: ui.W, - Expand: true, - }) - } + }, + { + Buttons: []magicform.Field{ + { + Label: "Open profile directory", + Font: balance.UIFont, + ButtonStyle: &balance.ButtonPrimary, + OnClick: func() { + path := strings.ReplaceAll(userdir.ProfileDirectory, "\\", "/") + if path[0] != '/' { + path = "/" + path + } + native.OpenURL("file://" + path) + }, + }, + }, + }, + }) return tab } @@ -575,7 +365,7 @@ func (c Settings) makeControlsTab(tabFrame *ui.TabFrame, Width, Height int) *ui. frame.Pack(curFrame, ui.Pack{ Side: ui.N, 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{ { - Label: "About", + Label: "Play with an Xbox or Nintendo controller!", Font: balance.LabelFont, }, { - Label: "Play Sketchy Maze with an Xbox or Nintendo controller!\n\n" + - "Full customization options aren't here yet, but you can\n" + - "choose between the 'X Style' or 'N Style' profile below.\n" + - "'N Style' will swap the A/B and X/Y buttons.", + Label: "If you have a Nintendo-style controller (your A button is on\n" + + "the right and B button on bottom), pick 'N Style' to reverse\n" + + "the A/B and X/Y buttons.", 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, }, {