Skip to content

Commit

Permalink
A menu listing savestates based on the date (#150)
Browse files Browse the repository at this point in the history
* A menu listing savestates based on the date

* Savestates screenshots

* Separation of concerns

* Refresh the savestates list on save

* Add a state icon
  • Loading branch information
kivutar authored Feb 12, 2019
1 parent 6b38277 commit 0b062ee
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 27 deletions.
2 changes: 1 addition & 1 deletion assets
Submodule assets updated 2 files
+ icon.ico
+ states.png
27 changes: 4 additions & 23 deletions menu/scene_quick.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package menu

import (
ntf "github.com/libretro/ludo/notifications"
"github.com/libretro/ludo/savestates"
"github.com/libretro/ludo/state"
)

Expand Down Expand Up @@ -32,29 +31,11 @@ func buildQuickMenu() Scene {
})

list.children = append(list.children, entry{
label: "Save State",
icon: "savestate",
label: "Savestates",
icon: "states",
callbackOK: func() {
err := savestates.Save()
if err != nil {
ntf.DisplayAndLog(ntf.Error, "Menu", err.Error())
} else {
ntf.DisplayAndLog(ntf.Success, "Menu", "State saved.")
}
},
})

list.children = append(list.children, entry{
label: "Load State",
icon: "loadstate",
callbackOK: func() {
err := savestates.Load()
if err != nil {
ntf.DisplayAndLog(ntf.Error, "Menu", err.Error())
} else {
state.Global.MenuActive = false
ntf.DisplayAndLog(ntf.Success, "Menu", "State loaded.")
}
list.segueNext()
menu.stack = append(menu.stack, buildSavestates())
},
})

Expand Down
138 changes: 138 additions & 0 deletions menu/scene_savestates.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package menu

import (
"path/filepath"
"sort"
"strings"

ntf "github.com/libretro/ludo/notifications"
"github.com/libretro/ludo/savestates"
"github.com/libretro/ludo/settings"
"github.com/libretro/ludo/state"
"github.com/libretro/ludo/utils"
"github.com/libretro/ludo/video"
)

type screenSavestates struct {
entry
}

func buildSavestates() Scene {
var list screenSavestates
list.label = "Savestates"

list.children = append(list.children, entry{
label: "Save State",
icon: "savestate",
callbackOK: func() {
vid.TakeScreenshot()
err := savestates.Save()
if err != nil {
ntf.DisplayAndLog(ntf.Error, "Menu", err.Error())
} else {
menu.stack[len(menu.stack)-1] = buildSavestates()
fastForwardTweens()
ntf.DisplayAndLog(ntf.Success, "Menu", "State saved.")
}
},
})

gameName := utils.Filename(state.Global.GamePath)
paths, _ := filepath.Glob(settings.Current.SavestatesDirectory + "/" + gameName + "@*.state")
sort.Sort(sort.Reverse(sort.StringSlice(paths)))
for _, path := range paths {
path := path
date := strings.Replace(utils.Filename(path), gameName+"@", "", 1)
list.children = append(list.children, entry{
label: "Load " + date,
icon: "loadstate",
path: path,
callbackOK: func() {
err := savestates.Load(path)
if err != nil {
ntf.DisplayAndLog(ntf.Error, "Menu", err.Error())
} else {
state.Global.MenuActive = false
ntf.DisplayAndLog(ntf.Success, "Menu", "State loaded.")
}
},
})
}

list.segueMount()

return &list
}

func (s *screenSavestates) Entry() *entry {
return &s.entry
}

func (s *screenSavestates) segueMount() {
genericSegueMount(&s.entry)
}

func (s *screenSavestates) segueNext() {
genericSegueNext(&s.entry)
}

func (s *screenSavestates) segueBack() {
genericAnimate(&s.entry)
}

func (s *screenSavestates) update(dt float32) {
genericInput(&s.entry, dt)
}

// Override rendering
func (s *screenSavestates) render() {
list := &s.entry

_, h := vid.Window.GetFramebufferSize()

for i, e := range list.children {
if e.yp < -0.1 || e.yp > 1.1 {
continue
}

fontOffset := 64 * 0.7 * menu.ratio * 0.3

color := video.Color{R: 0, G: 0, B: 0, A: e.iconAlpha}
if state.Global.CoreRunning {
color = video.Color{R: 1, G: 1, B: 1, A: e.iconAlpha}
}

if e.labelAlpha > 0 {
drawSavestateThumbnail(
list, i,
filepath.Join(settings.Current.ScreenshotsDirectory, utils.Filename(e.path)+".png"),
680*menu.ratio-85*e.scale*menu.ratio,
float32(h)*e.yp-14*menu.ratio-64*e.scale*menu.ratio+fontOffset,
170*menu.ratio, 128*menu.ratio,
e.scale, video.Color{R: 1, G: 1, B: 1, A: e.iconAlpha},
)
vid.DrawBorder(
680*menu.ratio-85*e.scale*menu.ratio,
float32(h)*e.yp-14*menu.ratio-64*e.scale*menu.ratio+fontOffset,
170*menu.ratio*e.scale, 128*menu.ratio*e.scale, 0.02/e.scale,
video.Color{R: color.R, G: color.G, B: color.B, A: e.iconAlpha})
if i == 0 {
vid.DrawImage(menu.icons["savestate"],
680*menu.ratio-64*e.scale*menu.ratio,
float32(h)*e.yp-14*menu.ratio-64*e.scale*menu.ratio+fontOffset,
128*menu.ratio, 128*menu.ratio,
e.scale, video.Color{R: 1, G: 1, B: 1, A: e.iconAlpha})
}

vid.Font.SetColor(color.R, color.G, color.B, e.labelAlpha)
vid.Font.Printf(
840*menu.ratio,
float32(h)*e.yp+fontOffset,
0.6*menu.ratio, e.label)
}
}
}

func (s *screenSavestates) drawHintBar() {
genericDrawHintBar()
}
14 changes: 14 additions & 0 deletions menu/thumbnail.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,17 @@ func drawThumbnail(list *entry, i int, system, gameName string, x, y, w, h, scal
color,
)
}

func drawSavestateThumbnail(list *entry, i int, path string, x, y, w, h, scale float32, color video.Color) {
if list.children[i].thumbnail == 0 {
if _, err := os.Stat(path); !os.IsNotExist(err) {
list.children[i].thumbnail = video.NewImage(path)
}
}

vid.DrawImage(
list.children[i].thumbnail,
x, y, w, h, scale,
color,
)
}
7 changes: 4 additions & 3 deletions savestates/savestates.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"time"

"github.com/libretro/ludo/settings"
"github.com/libretro/ludo/state"
Expand All @@ -15,7 +16,8 @@ func name() string {
name := filepath.Base(state.Global.GamePath)
ext := filepath.Ext(name)
name = name[0 : len(name)-len(ext)]
return name + ".state"
date := time.Now().Format("2006-01-02-15-04-05")
return name + "@" + date + ".state"
}

// Save the current state to the filesystem
Expand All @@ -34,9 +36,8 @@ func Save() error {
}

// Load the state from the filesystem
func Load() error {
func Load(path string) error {
s := state.Global.Core.SerializeSize()
path := filepath.Join(settings.Current.SavestatesDirectory, name())
bytes, err := ioutil.ReadFile(path)
if err != nil {
return err
Expand Down

0 comments on commit 0b062ee

Please sign in to comment.