...

Source file src/codeberg.org/tslocum/etk/sprite.go

Documentation: codeberg.org/tslocum/etk

     1  package etk
     2  
     3  import (
     4  	"image"
     5  
     6  	"github.com/hajimehoshi/ebiten/v2"
     7  )
     8  
     9  // Sprite is a resizable image.
    10  type Sprite struct {
    11  	*Box
    12  
    13  	img       *ebiten.Image
    14  	imgBounds image.Rectangle
    15  
    16  	thumb       *ebiten.Image
    17  	thumbBounds image.Rectangle
    18  
    19  	horizontal Alignment
    20  	vertical   Alignment
    21  }
    22  
    23  // NewSprite returns a new Sprite widget.
    24  func NewSprite(img *ebiten.Image) *Sprite {
    25  	return &Sprite{
    26  		Box:        NewBox(),
    27  		img:        img,
    28  		imgBounds:  img.Bounds(),
    29  		horizontal: AlignCenter,
    30  		vertical:   AlignCenter,
    31  	}
    32  }
    33  
    34  // SetImage sets the image of the Sprite.
    35  func (s *Sprite) SetImage(img *ebiten.Image) {
    36  	s.Lock()
    37  	defer s.Unlock()
    38  
    39  	s.img = img
    40  	s.imgBounds = s.img.Bounds()
    41  	s.thumbBounds = image.Rectangle{}
    42  }
    43  
    44  // SetHorizontal sets the horizontal alignment of the Sprite.
    45  func (s *Sprite) SetHorizontal(h Alignment) {
    46  	s.Lock()
    47  	defer s.Unlock()
    48  
    49  	s.horizontal = h
    50  	s.thumbBounds = image.Rectangle{}
    51  }
    52  
    53  // SetVertical sets the vertical alignment of the Sprite.
    54  func (s *Sprite) SetVertical(v Alignment) {
    55  	s.Lock()
    56  	defer s.Unlock()
    57  
    58  	s.vertical = v
    59  	s.thumbBounds = image.Rectangle{}
    60  }
    61  
    62  // Draw draws the Sprite on the screen.
    63  func (s *Sprite) Draw(screen *ebiten.Image) error {
    64  	s.Lock()
    65  	defer s.Unlock()
    66  
    67  	if s.rect.Dx() == 0 || s.rect.Dy() == 0 {
    68  		return nil // The Sprite has no size. Don't draw anything.
    69  	}
    70  
    71  	op := &ebiten.DrawImageOptions{}
    72  	op.GeoM.Translate(float64(s.rect.Min.X), float64(s.rect.Min.Y))
    73  	if s.imgBounds.Dx() == s.rect.Dx() && s.imgBounds.Dy() == s.rect.Dy() {
    74  		screen.DrawImage(s.img, op)
    75  		return nil
    76  	} else if s.thumb == nil || s.thumbBounds.Dx() != s.rect.Dx() || s.thumbBounds.Dy() != s.rect.Dy() {
    77  		scale, yScale := float64(s.rect.Dx())/float64(s.imgBounds.Dx()), float64(s.rect.Dy())/float64(s.imgBounds.Dy())
    78  		if yScale < scale {
    79  			scale = yScale
    80  		}
    81  		thumbOp := &ebiten.DrawImageOptions{}
    82  		thumbOp.GeoM.Scale(scale, scale)
    83  		if s.horizontal != AlignStart {
    84  			delta := float64(s.rect.Dx()) - float64(s.imgBounds.Dx())*scale
    85  			if s.horizontal == AlignCenter {
    86  				thumbOp.GeoM.Translate(delta/2, 0)
    87  			} else { // AlignEnd
    88  				thumbOp.GeoM.Translate(delta, 0)
    89  			}
    90  		}
    91  		if s.vertical != AlignStart {
    92  			delta := float64(s.rect.Dy()) - float64(s.imgBounds.Dy())*scale
    93  			if s.vertical == AlignCenter {
    94  				thumbOp.GeoM.Translate(0, delta/2)
    95  			} else { // AlignEnd
    96  				thumbOp.GeoM.Translate(0, delta)
    97  			}
    98  		}
    99  		createThumb := s.thumb == nil
   100  		if !createThumb {
   101  			bounds := s.thumb.Bounds()
   102  			createThumb = bounds.Dx() != s.rect.Dx() || bounds.Dy() != s.rect.Dy()
   103  		}
   104  		if createThumb {
   105  			s.thumb = ebiten.NewImage(s.rect.Dx(), s.rect.Dy())
   106  		}
   107  		s.thumb.DrawImage(s.img, thumbOp)
   108  		s.thumbBounds = s.thumb.Bounds()
   109  	}
   110  	screen.DrawImage(s.thumb, op)
   111  	return nil
   112  }
   113  

View as plain text