adam-gui/vendor/fyne.io/fyne/v2/widget/fileicon.go
2024-04-29 19:13:50 +02:00

204 lines
4.5 KiB
Go

package widget
import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/internal/repository/mime"
"fyne.io/fyne/v2/internal/widget"
"fyne.io/fyne/v2/storage"
"fyne.io/fyne/v2/theme"
)
const (
ratioDown = 0.45
ratioTextSize = 0.22
)
// FileIcon is an adaption of widget.Icon for showing files and folders
//
// Since: 1.4
type FileIcon struct {
BaseWidget
// Deprecated: Selection is now handled externally.
Selected bool
URI fyne.URI
resource fyne.Resource
extension string
}
// NewFileIcon takes a filepath and creates an icon with an overlaid label using the detected mimetype and extension
//
// Since: 1.4
func NewFileIcon(uri fyne.URI) *FileIcon {
i := &FileIcon{URI: uri}
i.ExtendBaseWidget(i)
return i
}
// SetURI changes the URI and makes the icon reflect a different file
func (i *FileIcon) SetURI(uri fyne.URI) {
i.URI = uri
i.Refresh()
}
func (i *FileIcon) setURI(uri fyne.URI) {
if uri == nil {
i.resource = theme.FileIcon()
return
}
i.URI = uri
i.resource = i.lookupIcon(i.URI)
i.extension = trimmedExtension(uri)
}
// MinSize returns the size that this widget should not shrink below
func (i *FileIcon) MinSize() fyne.Size {
i.ExtendBaseWidget(i)
return i.BaseWidget.MinSize()
}
// CreateRenderer is a private method to Fyne which links this widget to its renderer
func (i *FileIcon) CreateRenderer() fyne.WidgetRenderer {
i.ExtendBaseWidget(i)
i.propertyLock.Lock()
i.setURI(i.URI)
i.propertyLock.Unlock()
i.propertyLock.RLock()
defer i.propertyLock.RUnlock()
// TODO remove background when `SetSelected` is gone.
background := canvas.NewRectangle(theme.SelectionColor())
background.Hide()
s := &fileIconRenderer{file: i, background: background}
s.img = canvas.NewImageFromResource(s.file.resource)
s.img.FillMode = canvas.ImageFillContain
s.ext = canvas.NewText(s.file.extension, theme.BackgroundColor())
s.ext.Alignment = fyne.TextAlignCenter
s.SetObjects([]fyne.CanvasObject{s.background, s.img, s.ext})
return s
}
// SetSelected makes the file look like it is selected.
//
// Deprecated: Selection is now handled externally.
func (i *FileIcon) SetSelected(selected bool) {
i.Selected = selected
i.Refresh()
}
func (i *FileIcon) lookupIcon(uri fyne.URI) fyne.Resource {
if i.isDir(uri) {
return theme.FolderIcon()
}
mainMimeType, _ := mime.Split(uri.MimeType())
switch mainMimeType {
case "application":
return theme.FileApplicationIcon()
case "audio":
return theme.FileAudioIcon()
case "image":
return theme.FileImageIcon()
case "text":
return theme.FileTextIcon()
case "video":
return theme.FileVideoIcon()
default:
return theme.FileIcon()
}
}
func (i *FileIcon) isDir(uri fyne.URI) bool {
if _, ok := uri.(fyne.ListableURI); ok {
return true
}
listable, err := storage.ListerForURI(uri)
if err != nil {
return false
}
i.URI = listable // Avoid having to call storage.ListerForURI(uri) the next time.
return true
}
type fileIconRenderer struct {
widget.BaseRenderer
file *FileIcon
background *canvas.Rectangle
ext *canvas.Text
img *canvas.Image
}
func (s *fileIconRenderer) MinSize() fyne.Size {
return fyne.NewSquareSize(theme.IconInlineSize())
}
func (s *fileIconRenderer) Layout(size fyne.Size) {
isize := fyne.Min(size.Width, size.Height)
xoff := float32(0)
yoff := (size.Height - isize) / 2
if size.Width > size.Height {
xoff = (size.Width - isize) / 2
}
yoff += isize * ratioDown
oldSize := s.ext.TextSize
s.ext.TextSize = float32(int(isize * ratioTextSize))
s.ext.Resize(fyne.NewSize(isize, s.ext.MinSize().Height))
s.ext.Move(fyne.NewPos(xoff, yoff))
if oldSize != s.ext.TextSize {
s.ext.Refresh()
}
s.Objects()[0].Resize(size)
s.Objects()[1].Resize(size)
}
func (s *fileIconRenderer) Refresh() {
s.file.propertyLock.Lock()
s.file.setURI(s.file.URI)
s.file.propertyLock.Unlock()
s.file.propertyLock.RLock()
s.img.Resource = s.file.resource
s.ext.Text = s.file.extension
s.file.propertyLock.RUnlock()
if s.file.Selected {
s.background.Show()
s.ext.Color = theme.SelectionColor()
if _, ok := s.img.Resource.(*theme.InvertedThemedResource); !ok {
s.img.Resource = theme.NewInvertedThemedResource(s.img.Resource)
}
} else {
s.background.Hide()
s.ext.Color = theme.BackgroundColor()
if res, ok := s.img.Resource.(*theme.InvertedThemedResource); ok {
s.img.Resource = res.Original()
}
}
canvas.Refresh(s.file.super())
canvas.Refresh(s.ext)
}
func trimmedExtension(uri fyne.URI) string {
ext := uri.Extension()
if len(ext) > 5 {
ext = ext[:5]
}
return ext
}