Resources and images
A resource is a named block of bytes, such as an image, an icon or a
font. Anything in Bellui that shows an image takes a
bellui.Resource:
canvas.NewImageFromResource, widget.NewIcon, widget.NewButtonWithIcon,
App.SetIcon and more. The interface has two methods, Name() and
Content(). The name identifies the resource, and its extension tells
Bellui the format, so an SVG file’s name should end in .svg.
Embed files in your binary
Go’s embed package puts a file into the compiled program.
bellui.NewStaticResource
turns the bytes into a resource:
//go:embed logo.svg
var logoSVG []byte
// The name identifies the resource; keep the file extension, so an SVG
// is recognised as one.
var logo = bellui.NewStaticResource("logo.svg", logoSVG)The file logo.svg sits next to main.go. Embedded resources need no file
at run time, so this works the same on desktop, mobile and web.
Once you have a resource, use it wherever an image is wanted:
// One resource, used three ways.
a.SetIcon(logo) // the app icon, and the default icon of new windows
embedded := canvas.NewImageFromResource(logo)
embedded.FillMode = canvas.ImageFillContain
button := widget.NewButtonWithIcon("Logo", logo, func() {})Theme icons
The theme package
has a function for each standard icon: theme.HomeIcon(),
theme.SettingsIcon(), theme.SearchIcon(), theme.DeleteIcon(),
theme.InfoIcon() and many more. theme.Icon(name) looks one up by its
theme.IconName... constant. The standard icons take their colour from the
current theme, so they look right in light and dark mode.
To give your own single-colour SVG the same behaviour, wrap it.
theme.NewThemedResource uses the foreground colour;
theme.NewPrimaryThemedResource, NewErrorThemedResource,
NewWarningThemedResource and NewSuccessThemedResource use those colours.
theme.NewColoredResource(res, name) takes any theme colour name.
// Theme icons follow the current theme's colours and switch with it.
home := widget.NewIcon(theme.HomeIcon())
// Wrap your own monochrome icon to give it the theme's primary colour.
tinted := widget.NewIcon(theme.NewPrimaryThemedResource(logo))Load images at run time
When the image is not known at build time, load it:
| Function | Source |
|---|---|
canvas.NewImageFromFile(path) | A file path |
canvas.NewImageFromURI(uri) | A bellui.URI: a file, or another scheme such as https |
canvas.NewImageFromReader(r, name) | Any io.Reader; the name identifies it and gives its format |
canvas.NewImageFromImage(img) | A Go image.Image you already have |
if len(os.Args) > 1 {
// A file:// URI is read straight from disk.
fromDisk := canvas.NewImageFromURI(storage.NewFileURI(os.Args[1]))
fromDisk.FillMode = canvas.ImageFillContain
items = append(items, fromDisk)
}storage.NewFileURI
makes a URI from a path. For a file URI, NewImageFromURI is the same as
NewImageFromFile with that path.
file, NewImageFromURI downloads the data
before it returns. Do not call it with a network URI from a callback, or the
window freezes until the download ends. Load it on a goroutine and set the
image with bellui.Do.To make a resource rather than an image:
bellui.LoadResourceFromPath(path)reads a file into a static resource.storage.LoadResourceFromURI(uri)does the same for a URI.bellui.NewLazyResource(name, loader)andNewLazyResourceFromPath(path)load their bytes on first use and keep them.Release()frees the bytes; the next use loads them again.storage.NewAssetBundle(dir)serves a directory of files as lazily loaded resources, by relative name.
The whole example
// Images from three sources: a file embedded in the binary, the theme's
// icon set, and a file on disk named on the command line.
package main
import (
_ "embed"
"os"
"github.com/belluikit/bellui"
"github.com/belluikit/bellui/app"
"github.com/belluikit/bellui/canvas"
"github.com/belluikit/bellui/container"
"github.com/belluikit/bellui/core"
"github.com/belluikit/bellui/geo"
"github.com/belluikit/bellui/storage"
"github.com/belluikit/bellui/theme"
"github.com/belluikit/bellui/widget"
)
//go:embed logo.svg
var logoSVG []byte
// The name identifies the resource; keep the file extension, so an SVG
// is recognised as one.
var logo = bellui.NewStaticResource("logo.svg", logoSVG)
func main() {
a := app.NewWithID("com.example.resources")
w := a.NewWindow("Resources")
// One resource, used three ways.
a.SetIcon(logo) // the app icon, and the default icon of new windows
embedded := canvas.NewImageFromResource(logo)
embedded.FillMode = canvas.ImageFillContain
button := widget.NewButtonWithIcon("Logo", logo, func() {})
// Theme icons follow the current theme's colours and switch with it.
home := widget.NewIcon(theme.HomeIcon())
// Wrap your own monochrome icon to give it the theme's primary colour.
tinted := widget.NewIcon(theme.NewPrimaryThemedResource(logo))
items := []core.CanvasObject{embedded, button, home, tinted}
if len(os.Args) > 1 {
// A file:// URI is read straight from disk.
fromDisk := canvas.NewImageFromURI(storage.NewFileURI(os.Args[1]))
fromDisk.FillMode = canvas.ImageFillContain
items = append(items, fromDisk)
}
w.SetContent(container.NewGridWrap(geo.NewSize(96, 96), items...))
w.Resize(geo.NewSize(480, 240))
bellui.ShowAndRun(w)
}Run it with an image path to also show an image loaded from disk:
go run . ~/Pictures/photo.png