This repository has been archived on 2023-08-08. You can view files and clone it, but cannot push or open issues or pull requests.
tomo-old/elements/file/file.go
2023-03-21 18:03:31 -04:00

140 lines
3.3 KiB
Go

package fileElements
import "io/fs"
import "image"
import "git.tebibyte.media/sashakoshka/tomo/theme"
import "git.tebibyte.media/sashakoshka/tomo/artist"
import "git.tebibyte.media/sashakoshka/tomo/config"
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
// File displays an interactive visual representation of a file within any
// file system.
type File struct {
*core.Core
*core.FocusableCore
core core.CoreControl
focusableControl core.FocusableCoreControl
config config.Wrapped
theme theme.Wrapped
iconID theme.Icon
filesystem fs.StatFS
location string
onChoose func ()
}
// NewFile creates a new file element. If within is nil, it will use the OS file
// system
func NewFile (
location string,
within fs.StatFS,
) (
element *File,
err error,
) {
element = &File { }
element.theme.Case = theme.C("files", "file")
element.Core, element.core = core.NewCore(element, element.drawAll)
element.FocusableCore,
element.focusableControl = core.NewFocusableCore(element.core, element.drawAndPush)
err = element.SetLocation(location, within)
return
}
// Location returns the file's location and filesystem.
func (element *File) Location () (string, fs.StatFS) {
return element.location, element.filesystem
}
// SetLocation sets the file's location and filesystem. If within is nil, it
// will use the OS file system.
func (element *File) SetLocation (
location string,
within fs.StatFS,
) error {
if within == nil {
within = defaultFS { }
}
element.location = location
element.filesystem = within
return element.Update()
}
// Update refreshes the element to match the file it represents.
func (element *File) Update () error {
element.iconID = theme.IconError
info, err := element.filesystem.Stat(element.location)
if err != nil { return err }
// TODO: choose icon based on file mime type
if info.IsDir() {
element.iconID = theme.IconDirectory
} else {
element.iconID = theme.IconFile
}
element.updateMinimumSize()
element.drawAndPush()
return err
}
func (element *File) OnChoose (callback func ()) {
element.onChoose = callback
}
func (element *File) state () theme.State {
return theme.State {
Disabled: !element.Enabled(),
Focused: element.Focused(),
// Pressed: element.pressed,
}
}
func (element *File) icon () artist.Icon {
return element.theme.Icon(element.iconID, theme.IconSizeLarge)
}
func (element *File) updateMinimumSize () {
padding := element.theme.Padding(theme.PatternButton)
icon := element.icon()
if icon == nil {
element.core.SetMinimumSize (
padding.Horizontal(),
padding.Vertical())
} else {
bounds := padding.Inverse().Apply(icon.Bounds())
element.core.SetMinimumSize(bounds.Dx(), bounds.Dy())
}
}
func (element *File) drawAndPush () {
if element.core.HasImage() {
element.drawAll()
element.core.DamageAll()
}
}
func (element *File) drawAll () {
// background
state := element.state()
bounds := element.Bounds()
element.theme.
Pattern(theme.PatternButton, state).
Draw(element.core, bounds)
// icon
icon := element.icon()
if icon != nil {
iconBounds := icon.Bounds()
offset := image.Pt (
(bounds.Dx() - iconBounds.Dx()) / 2,
(bounds.Dy() - iconBounds.Dy()) / 2)
icon.Draw (
element.core,
element.theme.Color (
theme.ColorForeground, state),
bounds.Min.Add(offset))
}
}