Resources only exposes OpenResource (and Destroy).
PhysicalResources derives from Resources and exposes FetchResource. Made dependency specific resource addons. Extended the available resource options (fallback, path, refactored copy). NewRenderer provides DefaultResources to the created renderer.
This commit is contained in:
parent
869f87dd4f
commit
67e73a8671
23
addons/aferores/afero.go
Normal file
23
addons/aferores/afero.go
Normal file
@ -0,0 +1,23 @@
|
||||
package aferores
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/spf13/afero"
|
||||
"opslag.de/schobers/zntg/ui"
|
||||
)
|
||||
|
||||
type aferoResources struct {
|
||||
afero.Fs
|
||||
}
|
||||
|
||||
var _ ui.Resources = &aferoResources{}
|
||||
|
||||
// New provides resources from a afero file system.
|
||||
func New(fs afero.Fs) ui.Resources {
|
||||
return &aferoResources{fs}
|
||||
}
|
||||
|
||||
func (r *aferoResources) Destroy() error { return nil }
|
||||
|
||||
func (r *aferoResources) OpenResource(name string) (io.ReadCloser, error) { return r.Fs.Open(name) }
|
@ -1,76 +0,0 @@
|
||||
package res
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/afero"
|
||||
"opslag.de/schobers/zntg"
|
||||
"opslag.de/schobers/zntg/ui"
|
||||
)
|
||||
|
||||
type aferoResources struct {
|
||||
dir string
|
||||
fs afero.Fs
|
||||
copy *zntg.Dir
|
||||
}
|
||||
|
||||
var _ ui.Resources = &aferoResources{}
|
||||
|
||||
// NewAferoResources provides resources from a afero file system. The prefix is used as a prefix of the temporary directory.
|
||||
func NewAferoResources(fs afero.Fs, prefix string) (ui.Resources, error) {
|
||||
return NewAferoFallbackResources("", fs, prefix)
|
||||
}
|
||||
|
||||
// NewAferoFallbackResources provides resources from the directory first and uses afero file system as a fallback if the resource in the directory doesn't exist. The prefix is used as a prefix of the temporary directory.
|
||||
func NewAferoFallbackResources(dir string, fs afero.Fs, prefix string) (ui.Resources, error) {
|
||||
copy, err := zntg.NewTempDir(prefix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &aferoResources{dir, fs, copy}, nil
|
||||
}
|
||||
|
||||
func (r *aferoResources) fetchAferoResource(name string) (string, error) {
|
||||
path := r.copy.FilePath(name)
|
||||
if !zntg.FileExists(path) {
|
||||
src, err := r.fs.Open(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer src.Close()
|
||||
|
||||
err = r.copy.Write(name, src)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
|
||||
func (r *aferoResources) openAferoResource(name string) (io.ReadCloser, error) { return r.fs.Open(name) }
|
||||
|
||||
func (r *aferoResources) Destroy() error { return r.copy.Destroy() }
|
||||
|
||||
func (r *aferoResources) FetchResource(name string) (string, error) {
|
||||
if r.dir == "" {
|
||||
return r.fetchAferoResource(name)
|
||||
}
|
||||
path := filepath.Join(r.dir, name)
|
||||
if zntg.FileExists(path) {
|
||||
return path, nil
|
||||
}
|
||||
return r.fetchAferoResource(name)
|
||||
}
|
||||
|
||||
func (r *aferoResources) OpenResource(name string) (io.ReadCloser, error) {
|
||||
if r.dir == "" {
|
||||
return r.openAferoResource(name)
|
||||
}
|
||||
path := filepath.Join(r.dir, name)
|
||||
if zntg.FileExists(path) {
|
||||
return os.Open(path)
|
||||
}
|
||||
return r.openAferoResource(name)
|
||||
}
|
23
addons/riceres/rice.go
Normal file
23
addons/riceres/rice.go
Normal file
@ -0,0 +1,23 @@
|
||||
package riceres
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
rice "github.com/GeertJohan/go.rice"
|
||||
"opslag.de/schobers/zntg/ui"
|
||||
)
|
||||
|
||||
type riceResources struct {
|
||||
*rice.Box
|
||||
}
|
||||
|
||||
var _ ui.Resources = &riceResources{}
|
||||
|
||||
// New provides resources from a rice Box.
|
||||
func New(box *rice.Box) ui.Resources {
|
||||
return &riceResources{box}
|
||||
}
|
||||
|
||||
func (r *riceResources) Destroy() error { return nil }
|
||||
|
||||
func (r *riceResources) OpenResource(name string) (io.ReadCloser, error) { return r.Box.Open(name) }
|
@ -56,7 +56,7 @@ type Renderer struct {
|
||||
eq *allg5.EventQueue
|
||||
unh func(allg5.Event)
|
||||
user *allg5.UserEventSource
|
||||
res ui.Resources
|
||||
res ui.PhysicalResources
|
||||
|
||||
dispPos geom.Point
|
||||
keys ui.KeyState
|
||||
@ -335,7 +335,11 @@ func (r *Renderer) SetResourceProvider(factory func() ui.Resources) {
|
||||
if r.res != nil {
|
||||
r.res.Destroy()
|
||||
}
|
||||
r.res = factory()
|
||||
res, err := ui.NewCopyResources("allg5ui", factory(), false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
r.res = res
|
||||
}
|
||||
|
||||
func (r *Renderer) SetUnhandledEventHandler(handler func(allg5.Event)) {
|
||||
|
@ -22,7 +22,7 @@ type Renderer struct {
|
||||
window *sdl.Window
|
||||
renderer *sdl.Renderer
|
||||
refresh uint32
|
||||
resources ui.Resources
|
||||
resources ui.PhysicalResources
|
||||
|
||||
mouse geom.PointF32
|
||||
cursor ui.MouseCursor
|
||||
@ -477,7 +477,11 @@ func (r *Renderer) SetResourceProvider(factory func() ui.Resources) {
|
||||
if r.resources != nil {
|
||||
r.resources.Destroy()
|
||||
}
|
||||
r.resources = factory()
|
||||
resources, err := ui.NewCopyResources("sdlui", factory(), false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
r.resources = resources
|
||||
}
|
||||
|
||||
// Texture
|
||||
|
@ -7,22 +7,28 @@ import (
|
||||
"opslag.de/schobers/zntg"
|
||||
)
|
||||
|
||||
var _ Resources = &CopyResources{}
|
||||
var _ PhysicalResources = &CopyResources{}
|
||||
|
||||
// CopyResources copies and opens resources to a temporary directory.
|
||||
// CopyResources copies the resource to a temporary directory when fetched. Optionally the resource is fetched as well before opening.
|
||||
type CopyResources struct {
|
||||
Source Resources
|
||||
|
||||
copy *zntg.Dir
|
||||
|
||||
mustCopyBeforeOpen bool
|
||||
}
|
||||
|
||||
// NewCopyResource creates a proxy that copied resources first to disk.
|
||||
func NewCopyResource(prefix string, source Resources) (*CopyResources, error) {
|
||||
func newCopyResources(prefix string, source Resources, mustCopyBeforeOpen bool) (*CopyResources, error) {
|
||||
copy, err := zntg.NewTempDir(prefix)
|
||||
if nil != err {
|
||||
return nil, err
|
||||
}
|
||||
return &CopyResources{source, copy}, nil
|
||||
return &CopyResources{source, copy, mustCopyBeforeOpen}, nil
|
||||
}
|
||||
|
||||
// NewCopyResources creates a proxy that copies resources first to disk. Copy on OpenResource only happens when mustCopyBeforeOpen is set to true.
|
||||
func NewCopyResources(prefix string, source Resources, mustCopyBeforeOpen bool) (*CopyResources, error) {
|
||||
return newCopyResources(prefix, source, false)
|
||||
}
|
||||
|
||||
// FetchResource copies the file from the source to disk and returns the path to it.
|
||||
@ -43,11 +49,16 @@ func (r *CopyResources) FetchResource(name string) (string, error) {
|
||||
return path, nil
|
||||
}
|
||||
|
||||
// OpenResource opens the (copied) resource on disk.
|
||||
// OpenResource opens the (optionally copied) resource.
|
||||
func (r *CopyResources) OpenResource(name string) (io.ReadCloser, error) {
|
||||
path := r.copy.FilePath(name)
|
||||
src, err := os.Open(path)
|
||||
return src, err
|
||||
if r.mustCopyBeforeOpen {
|
||||
path, err := r.FetchResource(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return os.Open(path)
|
||||
}
|
||||
return r.Source.OpenResource(name)
|
||||
}
|
||||
|
||||
// Destroy destroy the copy of the resources.
|
||||
|
34
ui/fallbackresources.go
Normal file
34
ui/fallbackresources.go
Normal file
@ -0,0 +1,34 @@
|
||||
package ui
|
||||
|
||||
import "io"
|
||||
|
||||
var _ Resources = &fallbackResources{}
|
||||
|
||||
type fallbackResources struct {
|
||||
resources Resources
|
||||
fallback Resources
|
||||
}
|
||||
|
||||
// NewFallbackResources creates a Resources that first will try to access resources and on failure will try to access the fallback resources. Will take ownership of both resources (Destroy).
|
||||
func NewFallbackResources(resources, fallback Resources) Resources {
|
||||
return &fallbackResources{resources, fallback}
|
||||
}
|
||||
|
||||
func (r *fallbackResources) OpenResource(name string) (io.ReadCloser, error) {
|
||||
if reader, err := r.resources.OpenResource(name); err == nil {
|
||||
return reader, nil
|
||||
}
|
||||
return r.fallback.OpenResource(name)
|
||||
}
|
||||
|
||||
func (r *fallbackResources) Destroy() error {
|
||||
errResources := r.resources.Destroy()
|
||||
errFallback := r.fallback.Destroy()
|
||||
if errResources != nil {
|
||||
return errResources
|
||||
}
|
||||
if errFallback != nil {
|
||||
return errFallback
|
||||
}
|
||||
return nil
|
||||
}
|
@ -5,10 +5,10 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
var _ Resources = &OSResources{}
|
||||
var _ PhysicalResources = &OSResources{}
|
||||
|
||||
// DefaultResources returns the default Resources implementation (OSResources).
|
||||
func DefaultResources() Resources {
|
||||
func DefaultResources() PhysicalResources {
|
||||
return &OSResources{}
|
||||
}
|
||||
|
||||
|
62
ui/pathresources.go
Normal file
62
ui/pathresources.go
Normal file
@ -0,0 +1,62 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"io"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
var _ Resources = &PathResources{}
|
||||
|
||||
// PathResources implements Resources by adding a prefix to the requested source name before proxying it to its source.
|
||||
type PathResources struct {
|
||||
Source Resources
|
||||
Prefix string
|
||||
}
|
||||
|
||||
// NewPathResources creates a new Resources by adding a prefix to the requested source name before proxying it to its source. If source is nil it will use the OS file system for its resources.
|
||||
func NewPathResources(source Resources, prefix string) *PathResources {
|
||||
if source == nil {
|
||||
source = &OSResources{}
|
||||
}
|
||||
return &PathResources{source, prefix}
|
||||
}
|
||||
|
||||
// Destroy destroys the source.
|
||||
func (r *PathResources) Destroy() error { return r.Source.Destroy() }
|
||||
|
||||
// OpenResource opens the resource with the prefixed name.
|
||||
func (r *PathResources) OpenResource(name string) (io.ReadCloser, error) {
|
||||
path := filepath.Join(r.Prefix, name)
|
||||
return r.Source.OpenResource(path)
|
||||
}
|
||||
|
||||
var _ PhysicalResources = &PathPhysicalResources{}
|
||||
|
||||
// PathPhysicalResources implements PhysicalResources by adding a prefix to the requested source name before proxying it to its source.
|
||||
type PathPhysicalResources struct {
|
||||
Source PhysicalResources
|
||||
Prefix string
|
||||
}
|
||||
|
||||
// NewPathPhysicalResources creates a new PhysicalResources by adding a prefix to the requested source name before proxying it to its source. If source is nil it will use the OS file system for its resources.
|
||||
func NewPathPhysicalResources(source PhysicalResources, prefix string) *PathPhysicalResources {
|
||||
if source == nil {
|
||||
source = &OSResources{}
|
||||
}
|
||||
return &PathPhysicalResources{source, prefix}
|
||||
}
|
||||
|
||||
// Destroy destroys the source.
|
||||
func (r *PathPhysicalResources) Destroy() error { return r.Source.Destroy() }
|
||||
|
||||
// FetchResource fetches the resource with the prefixed name.
|
||||
func (r *PathPhysicalResources) FetchResource(name string) (string, error) {
|
||||
path := filepath.Join(r.Prefix, name)
|
||||
return r.Source.FetchResource(path)
|
||||
}
|
||||
|
||||
// OpenResource opens the resource with the prefixed name.
|
||||
func (r *PathPhysicalResources) OpenResource(name string) (io.ReadCloser, error) {
|
||||
path := filepath.Join(r.Prefix, name)
|
||||
return r.Source.OpenResource(path)
|
||||
}
|
@ -18,12 +18,17 @@ func NewRenderer(title string, width, height int, opts NewRendererOptions) (Rend
|
||||
if rendererFactory == nil {
|
||||
return nil, errors.New("no renderer factory registered")
|
||||
}
|
||||
return rendererFactory.New(title, width, height, opts)
|
||||
renderer, err := rendererFactory.New(title, width, height, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
renderer.SetResourceProvider(func() Resources { return DefaultResources() })
|
||||
return renderer, nil
|
||||
}
|
||||
|
||||
// NewRendererDefault creates a new renderer with default options set based on the registered renderer factory.
|
||||
func NewRendererDefault(title string, width, height int) (Renderer, error) {
|
||||
return rendererFactory.New(title, width, height, NewRendererOptions{
|
||||
return NewRenderer(title, width, height, NewRendererOptions{
|
||||
Resizable: true,
|
||||
})
|
||||
}
|
||||
|
@ -2,12 +2,18 @@ package ui
|
||||
|
||||
import "io"
|
||||
|
||||
// Resources is an abstraction on resources.
|
||||
// Resources is an abstraction for opening resources.
|
||||
type Resources interface {
|
||||
// FetchResource should fetch the resource with the specified name and return a path (on disk) where the resource can be accessed.
|
||||
FetchResource(name string) (string, error)
|
||||
// OpenResource should open the resource with the specified name. The user is responsible for closing the resource.
|
||||
OpenResource(name string) (io.ReadCloser, error)
|
||||
// Destroy can be used for cleaning up at the end of the applications lifetime.
|
||||
Destroy() error
|
||||
}
|
||||
|
||||
// PhysicalResources is an abstraction for opening and fetching (to disk) resources.
|
||||
type PhysicalResources interface {
|
||||
Resources
|
||||
|
||||
// FetchResource should fetch the resource with the specified name and return a path (on disk) where the resource can be accessed.
|
||||
FetchResource(name string) (string, error)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user