diff --git a/dev-assets/doodads/build.sh b/dev-assets/doodads/build.sh index 268dffd..4e20064 100755 --- a/dev-assets/doodads/build.sh +++ b/dev-assets/doodads/build.sh @@ -33,6 +33,9 @@ buttons() { doodad convert -t "Button Type B" typeB1.png typeB2.png button-typeB.doodad doodad install-script button.js button-typeB.doodad + # Tag the category for these doodads + for i in *.doodad; do doodad edit-doodad --tag "category=gizmos" $i; done + cp button*.doodad ../../../assets/doodads/ cd .. } @@ -50,6 +53,9 @@ switches() { doodad install-script switch.js switch-left.doodad doodad install-script switch.js switch-right.doodad + # Tag the category for these doodads + for i in *.doodad; do doodad edit-doodad --tag "category=gizmos" $i; done + cp *.doodad ../../../assets/doodads/ cd .. } @@ -77,6 +83,9 @@ trapdoors() { doodad edit-doodad -q --tag direction=right trapdoor-right.doodad doodad edit-doodad -q --tag direction=up trapdoor-up.doodad + # Tag the category for these doodads + for i in *.doodad; do doodad edit-doodad --tag "category=doors" $i; done + cp trapdoor-*.doodad ../../../assets/doodads/ cd .. @@ -93,6 +102,9 @@ azulians() { red-wr{1,2,3,4}.png red-wl{1,2,3,4}.png azu-red.doodad doodad install-script azulian-red.js azu-red.doodad + # Tag the category for these doodads + for i in *.doodad; do doodad edit-doodad --tag "category=creatures" $i; done + cp azu-*.doodad ../../../assets/doodads/ cd .. @@ -105,6 +117,9 @@ mobs() { dive-left.png dive-right.png bird-red.doodad doodad install-script bird.js bird-red.doodad + # Tag the category for these doodads + for i in *.doodad; do doodad edit-doodad --tag "category=creatures" $i; done + cp *.doodad ../../../assets/doodads/ cd .. } @@ -117,6 +132,7 @@ objects() { doodad convert -t "Start Flag" start-flag.png start-flag.doodad + for i in *.doodad; do doodad edit-doodad --tag "category=objects" $i; done cp *.doodad ../../../assets/doodads/ cd ../crumbly-floor @@ -125,12 +141,14 @@ objects() { fall1.png fall2.png fall3.png fall4.png fallen.png \ crumbly-floor.doodad doodad install-script crumbly-floor.js crumbly-floor.doodad + for i in *.doodad; do doodad edit-doodad --tag "category=objects" $i; done cp *.doodad ../../../assets/doodads/ cd ../box doodad convert -t "Box" box-1.png box-2.png box-3.png box-4.png box.doodad doodad install-script box.js box.doodad + for i in *.doodad; do doodad edit-doodad --tag "category=objects" $i; done cp *.doodad ../../../assets/doodads/ cd .. @@ -148,6 +166,8 @@ onoff() { doodad convert -t "State Block (Orange)" orange-off.png orange-on.png state-block-orange.doodad doodad install-script state-block-orange.js state-block-orange.doodad + for i in *.doodad; do doodad edit-doodad --tag "category=gizmos" $i; done + cp *.doodad ../../../assets/doodads/ cd .. @@ -170,6 +190,9 @@ warpdoor() { doodad edit-doodad -q --tag color=orange warp-door-orange.doodad doodad install-script warp-door.js warp-door-orange.doodad + for i in *.doodad; do doodad edit-doodad --tag "category=doors" $i; done + for i in warp-door-*.doodad; do doodad edit-doodad --tag "category=doors,gizmos" $i; done + cp *.doodad ../../../assets/doodads/ cd .. diff --git a/dev-assets/doodads/doors/build.sh b/dev-assets/doodads/doors/build.sh index 384d486..5f327d3 100755 --- a/dev-assets/doodads/doors/build.sh +++ b/dev-assets/doodads/doors/build.sh @@ -45,4 +45,8 @@ doodad install-script keys.js small-key.doodad doodad convert -t "Electric Door" electric{1,2,3,4}.png door-electric.doodad doodad install-script electric-door.js door-electric.doodad +# Tag the category for these doodads +for i in *.doodad; do doodad edit-doodad --tag "category=doors" $i; done +doodad edit-doodad --tag "category=doors,gizmos" door-electric.doodad + cp door-*.doodad key-*.doodad small-*.doodad ../../../assets/doodads/ diff --git a/go.mod b/go.mod index 5b63921..90e95a3 100644 --- a/go.mod +++ b/go.mod @@ -5,9 +5,9 @@ go 1.16 require ( git.kirsle.net/go/audio v0.0.0-20200429055451-ae3b0695ba6f git.kirsle.net/go/log v0.0.0-20200902035305-70ac2848949b - git.kirsle.net/go/render v0.0.0-20210104010442-b4a1979a8ba1 + git.kirsle.net/go/render v0.0.0-20210614025954-d77f5056b782 git.kirsle.net/go/ui v0.0.0-20200710023146-e2a561fbd04c - github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect + github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/fsnotify/fsnotify v1.4.9 github.com/gen2brain/dlgs v0.0.0-20210406143744-f512297a108e github.com/google/uuid v1.1.2 @@ -16,9 +16,9 @@ require ( github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac github.com/tomnomnom/xtermcolor v0.0.0-20160428124646-b78803f00a7e // indirect github.com/urfave/cli/v2 v2.3.0 - github.com/veandco/go-sdl2 v0.4.7 + github.com/veandco/go-sdl2 v0.4.8 github.com/vmihailenco/msgpack v3.3.3+incompatible - golang.org/x/image v0.0.0-20210504121937-7319ad40d33e + golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d google.golang.org/appengine v1.6.7 // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect gopkg.in/sourcemap.v1 v1.0.5 // indirect diff --git a/go.sum b/go.sum index f52d35d..915fe9b 100644 --- a/go.sum +++ b/go.sum @@ -191,8 +191,8 @@ github.com/tomnomnom/xtermcolor v0.0.0-20160428124646-b78803f00a7e/go.mod h1:fSI github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/veandco/go-sdl2 v0.4.1/go.mod h1:FB+kTpX9YTE+urhYiClnRzpOXbiWgaU3+5F2AB78DPg= -github.com/veandco/go-sdl2 v0.4.7 h1:VfpCM+LfEGDbHdByglCo2bcBsevjFvzl8W0f6VLNitg= -github.com/veandco/go-sdl2 v0.4.7/go.mod h1:OROqMhHD43nT4/i9crJukyVecjPNYYuCofep6SNiAjY= +github.com/veandco/go-sdl2 v0.4.8 h1:A26KeX6R1CGt/BQGEov6oxYmVGMMEWDVqTvK1tXvahE= +github.com/veandco/go-sdl2 v0.4.8/go.mod h1:OROqMhHD43nT4/i9crJukyVecjPNYYuCofep6SNiAjY= github.com/vmihailenco/msgpack v3.3.3+incompatible h1:wapg9xDUZDzGCNFlwc5SqI1rvcciqcxEHac4CYj89xI= github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= @@ -220,8 +220,8 @@ golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20210504121937-7319ad40d33e h1:PzJMNfFQx+QO9hrC1GwZ4BoPGeNGhfeQEgcQFArEjPk= -golang.org/x/image v0.0.0-20210504121937-7319ad40d33e/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d h1:RNPAfi2nHY7C2srAV8A49jpsYr0ADedCk1wq6fTMTvs= +golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -285,6 +285,7 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/pkg/balance/theme.go b/pkg/balance/theme.go index d65cb23..82319d8 100644 --- a/pkg/balance/theme.go +++ b/pkg/balance/theme.go @@ -73,6 +73,13 @@ var ( PadX: 4, } + // TabFrame styles. + TabFont = render.Text{ + Size: 12, + PadX: 8, + PadY: 4, + } + // Modal backdrop color. ModalBackdrop = render.RGBA(1, 1, 1, 42) diff --git a/pkg/doodads/sort.go b/pkg/doodads/sort.go new file mode 100644 index 0000000..7ba2821 --- /dev/null +++ b/pkg/doodads/sort.go @@ -0,0 +1,10 @@ +package doodads + +import "sort" + +// SortByName orders an array of loaded Doodads by their titles. +func SortByName(list []*Doodad) { + sort.SliceStable(list, func(i, j int) bool { + return list[i].Title < list[j].Title + }) +} diff --git a/pkg/windows/doodad_dropper.go b/pkg/windows/doodad_dropper.go index 26553e4..f6d7e47 100644 --- a/pkg/windows/doodad_dropper.go +++ b/pkg/windows/doodad_dropper.go @@ -3,6 +3,7 @@ package windows import ( "fmt" "math" + "strings" "git.kirsle.net/apps/doodle/pkg/balance" "git.kirsle.net/apps/doodle/pkg/doodads" @@ -40,33 +41,9 @@ func NewDoodadDropper(config DoodadDropper) *ui.Window { // size of the doodad window width = buttonSize * columns height = (buttonSize * rows) + 64 // account for button borders :( - - // pagination values - page = 1 - pages int - perPage = 20 - maxPageButtons = 10 ) - window := ui.NewWindow(title) - window.SetButtons(ui.CloseButton) - window.Configure(ui.Config{ - Width: width, - Height: height, - Background: render.Grey, - }) - - frame := ui.NewFrame("Window Body Frame") - window.Pack(frame, ui.Pack{ - Side: ui.N, - Fill: true, - Expand: true, - }) - - /******* - * Display the Doodads in rows of buttons - *******/ - + // Get all the doodads. doodadsAvailable, err := doodads.ListDoodads() if err != nil { log.Error("NewDoodadDropper: doodads.ListDoodads: %s", err) @@ -90,6 +67,76 @@ func NewDoodadDropper(config DoodadDropper) *ui.Window { items = append(items, doodad) } + window := ui.NewWindow(title) + window.SetButtons(ui.CloseButton) + window.Configure(ui.Config{ + Width: width, + Height: height + 30, + Background: render.Grey, + }) + + tabFrame := ui.NewTabFrame("Category Tabs") + window.Pack(tabFrame, ui.Pack{ + Side: ui.N, + Fill: true, + Expand: true, + }) + + // The Category Tabs. + categories := []struct { + ID string + Name string + }{ + {"objects", "Objects"}, + {"doors", "Doors"}, + {"gizmos", "Gizmos"}, + {"creatures", "Creatures"}, + {"", "All"}, + } + for _, category := range categories { + tab1 := tabFrame.AddTab(category.Name, ui.NewLabel(ui.Label{ + Text: category.Name, + Font: balance.TabFont, + })) + makeDoodadTab(config, tab1, render.NewRect(width-4, height-60), category.ID, items) + } + + tabFrame.Supervise(config.Supervisor) + + window.Hide() + return window +} + +// Function to generate the TabFrame frame of the Doodads window. +func makeDoodadTab(config DoodadDropper, frame *ui.Frame, size render.Rect, category string, available []*doodads.Doodad) { + var ( + buttonSize = balance.DoodadButtonSize + columns = balance.DoodadDropperCols + rows = balance.DoodadDropperRows + + // pagination values + page = 1 + pages int + perPage = 20 + maxPageButtons = 10 + ) + frame.Resize(size) + + // Trim the available doodads to those fitting the category. + var items = []*doodads.Doodad{} + for _, candidate := range available { + if value, ok := candidate.Tags["category"]; ok { + if category != "" && !strings.Contains(value, category) { + continue + } + } else if category != "" { + continue + } + items = append(items, candidate) + } + + doodads.SortByName(items) + // Compute the number of pages for the pager widget. pages = int( math.Ceil( @@ -176,7 +223,7 @@ func NewDoodadDropper(config DoodadDropper) *ui.Window { bottomFrame := ui.NewFrame("Button Frame") frame.Pack(bottomFrame, ui.Pack{ - Side: ui.S, + Side: ui.N, FillX: true, }) @@ -242,7 +289,4 @@ func NewDoodadDropper(config DoodadDropper) *ui.Window { }) } } - - window.Hide() - return window } diff --git a/pkg/windows/settings.go b/pkg/windows/settings.go index 45558cb..7a7d076 100644 --- a/pkg/windows/settings.go +++ b/pkg/windows/settings.go @@ -50,17 +50,9 @@ func MakeSettingsWindow(windowWidth, windowHeight int, cfg Settings) *ui.Window // NewSettingsWindow initializes the window. func NewSettingsWindow(cfg Settings) *ui.Window { var ( - Width = 400 - Height = 400 - ActiveTab = "index" - - // The tab frames - TabOptions *ui.Frame // index - TabControls *ui.Frame // controls + Width = 400 + Height = 400 ) - if cfg.ActiveTab != "" { - ActiveTab = cfg.ActiveTab - } window := ui.NewWindow("Settings") window.SetButtons(ui.CloseButton) @@ -72,63 +64,22 @@ func NewSettingsWindow(cfg Settings) *ui.Window { /////////// // Tab Bar - tabFrame := ui.NewFrame("Tab Bar") + tabFrame := ui.NewTabFrame("Tab Frame") tabFrame.SetBackground(render.DarkGrey) window.Pack(tabFrame, ui.Pack{ Side: ui.N, FillX: true, }) - for _, tab := range []struct { - label string - value string - }{ - {"Options", "index"}, - {"Controls", "controls"}, - } { - radio := ui.NewRadioButton(tab.label, &ActiveTab, tab.value, ui.NewLabel(ui.Label{ - Text: tab.label, - Font: balance.UIFont, - })) - radio.SetStyle(&balance.ButtonBabyBlue) - radio.Handle(ui.Click, func(ed ui.EventData) error { - switch ActiveTab { - case "index": - TabOptions.Show() - TabControls.Hide() - case "controls": - TabOptions.Hide() - TabControls.Show() - } - return nil - }) - cfg.Supervisor.Add(radio) - tabFrame.Pack(radio, ui.Pack{ - Side: ui.W, - Expand: true, - }) - } /////////// // Options (index) Tab - TabOptions = cfg.makeOptionsTab(Width, Height) - if ActiveTab != "index" { - TabOptions.Hide() - } - window.Pack(TabOptions, ui.Pack{ - Side: ui.N, - FillX: true, - }) + cfg.makeOptionsTab(tabFrame, Width, Height) /////////// // Controls Tab - TabControls = cfg.makeControlsTab(Width, Height) - if ActiveTab != "controls" { - TabControls.Hide() - } - window.Pack(TabControls, ui.Pack{ - Side: ui.N, - FillX: true, - }) + cfg.makeControlsTab(tabFrame, Width, Height) + + tabFrame.Supervise(cfg.Supervisor) return window } @@ -143,8 +94,12 @@ func saveGameSettings() { } // Settings Window "Options" Tab -func (c Settings) makeOptionsTab(Width, Height int) *ui.Frame { - tab := ui.NewFrame("Options Tab") +func (c Settings) makeOptionsTab(tabFrame *ui.TabFrame, Width, Height int) *ui.Frame { + tab := tabFrame.AddTab("Options", ui.NewLabel(ui.Label{ + Text: "Options", + Font: balance.TabFont, + })) + tab.Resize(render.NewRect(Width-4, Height-tab.Size().H-46)) // Common click handler for all settings, // so we can write the updated info to disk. @@ -307,7 +262,13 @@ func (c Settings) makeOptionsTab(Width, Height int) *ui.Frame { } // Settings Window "Controls" Tab -func (c Settings) makeControlsTab(Width, Height int) *ui.Frame { +func (c Settings) makeControlsTab(tabFrame *ui.TabFrame, Width, Height int) *ui.Frame { + frame := tabFrame.AddTab("Controls", ui.NewLabel(ui.Label{ + Text: "Controls", + Font: balance.TabFont, + })) + frame.Resize(render.NewRect(Width-4, Height-frame.Size().H-46)) + var ( halfWidth = (Width - 4) / 2 // the 4 is for window borders, TODO shortcutTabWidth = float64(halfWidth) * 0.5 @@ -317,7 +278,6 @@ func (c Settings) makeControlsTab(Width, Height int) *ui.Frame { shortcutTabSize = render.NewRect(int(shortcutTabWidth), rowHeight) infoTabSize = render.NewRect(int(infoTabWidth), rowHeight) ) - frame := ui.NewFrame("Controls Tab") controls := []struct { Header string