...

Source file src/code.rocket9labs.com/tslocum/etk/checkbox.go

Documentation: code.rocket9labs.com/tslocum/etk

     1  package etk
     2  
     3  import (
     4  	"image"
     5  	"image/color"
     6  
     7  	"github.com/hajimehoshi/ebiten/v2"
     8  	"github.com/llgcode/draw2d/draw2dimg"
     9  )
    10  
    11  // Checkbox is a toggleable Checkbox.
    12  type Checkbox struct {
    13  	*Box
    14  
    15  	selected    bool
    16  	checkColor  color.RGBA
    17  	borderSize  int
    18  	borderColor color.RGBA
    19  	baseImg     *image.RGBA
    20  	img         *ebiten.Image
    21  	onSelect    func() error
    22  }
    23  
    24  // NewCheckbox returns a new Checkbox widget.
    25  func NewCheckbox(onSelect func() error) *Checkbox {
    26  	return &Checkbox{
    27  		Box:         NewBox(),
    28  		checkColor:  Style.TextColorDark,
    29  		borderSize:  2,
    30  		borderColor: Style.BorderColorBottom,
    31  		onSelect:    onSelect,
    32  	}
    33  }
    34  
    35  // SetRect sets the position and size of the Checkbox. The checkbox is always
    36  // a square shape.
    37  func (c *Checkbox) SetRect(r image.Rectangle) {
    38  	if c.Box.rect.Eq(r) {
    39  		return
    40  	}
    41  
    42  	bounds := r.Bounds()
    43  	newSize := bounds.Dx()
    44  	if bounds.Dy() < newSize {
    45  		newSize = bounds.Dy()
    46  	}
    47  
    48  	if r.Dx() != newSize {
    49  		r.Max.X = r.Min.X + newSize
    50  	}
    51  	if r.Dy() != newSize {
    52  		r.Max.Y = r.Min.Y + newSize
    53  	}
    54  	c.Box.rect = r
    55  
    56  	c.updateImage()
    57  
    58  	for _, w := range c.children {
    59  		w.SetRect(r)
    60  	}
    61  }
    62  
    63  // SetCheckColor sets the check mark color of the Checkbox.
    64  func (c *Checkbox) SetCheckColor(checkColor color.RGBA) {
    65  	c.checkColor = checkColor
    66  	c.updateImage()
    67  }
    68  
    69  // SetBorderColor sets the border color of the Checkbox.
    70  func (c *Checkbox) SetBorderColor(borderColor color.RGBA) {
    71  	c.borderColor = borderColor
    72  	c.updateImage()
    73  }
    74  
    75  // Selected returns the selection state of the Checkbox.
    76  func (c *Checkbox) Selected() bool {
    77  	return c.selected
    78  }
    79  
    80  // SetSelected sets the Checkbox selection state. The onSelect function is not
    81  // called when the value is set manually via SetSelected.
    82  func (c *Checkbox) SetSelected(selected bool) {
    83  	if c.selected == selected {
    84  		return
    85  	}
    86  	c.selected = selected
    87  	c.updateImage()
    88  }
    89  
    90  // HandleKeyboard is called when a keyboard event occurs.
    91  func (c *Checkbox) HandleKeyboard(ebiten.Key, rune) (handled bool, err error) {
    92  	return false, nil
    93  }
    94  
    95  // HandleMouse is called when a mouse event occurs.
    96  func (c *Checkbox) HandleMouse(cursor image.Point, pressed bool, clicked bool) (handled bool, err error) {
    97  	if !clicked {
    98  		return true, nil
    99  	}
   100  
   101  	c.selected = !c.selected
   102  	c.updateImage()
   103  
   104  	c.Lock()
   105  	onSelect := c.onSelect
   106  	if onSelect == nil {
   107  		c.Unlock()
   108  		return true, nil
   109  	}
   110  	c.Unlock()
   111  
   112  	return true, onSelect()
   113  }
   114  
   115  func (c *Checkbox) updateImage() {
   116  	r := c.Rect()
   117  	if r.Empty() {
   118  		c.img = nil
   119  		return
   120  	}
   121  
   122  	bounds := r.Bounds()
   123  	newSize := bounds.Dx()
   124  	var initializeImg bool
   125  	if c.img == nil {
   126  		initializeImg = true
   127  	} else {
   128  		imgBounds := c.img.Bounds()
   129  		imgSize := imgBounds.Dx()
   130  		if imgSize != newSize {
   131  			initializeImg = true
   132  		}
   133  	}
   134  	if initializeImg {
   135  		c.baseImg = image.NewRGBA(rectAtOrigin(r))
   136  		c.img = ebiten.NewImage(newSize, newSize)
   137  	}
   138  
   139  	// Draw border.
   140  	c.img.Fill(c.borderColor)
   141  	c.img.SubImage(rectAtOrigin(r).Inset(c.borderSize)).(*ebiten.Image).Fill(color.RGBA64{0, 0, 0, 0})
   142  
   143  	// Draw check mark.
   144  	if !c.selected {
   145  		return
   146  	}
   147  	gc := draw2dimg.NewGraphicContext(c.baseImg)
   148  	gc.SetStrokeColor(c.checkColor)
   149  	gc.SetLineWidth(float64(c.borderSize))
   150  	gc.MoveTo(0, 0)
   151  	gc.LineTo(float64(r.Dx()), float64(r.Dy()))
   152  	gc.MoveTo(0, float64(r.Dy()))
   153  	gc.LineTo(float64(r.Dx()), 0)
   154  	gc.Stroke()
   155  	c.img.DrawImage(ebiten.NewImageFromImage(c.baseImg), nil)
   156  
   157  }
   158  
   159  // Draw draws the Checkbox on the screen.
   160  func (c *Checkbox) Draw(screen *ebiten.Image) error {
   161  	if c.img == nil {
   162  		return nil
   163  	}
   164  
   165  	op := &ebiten.DrawImageOptions{}
   166  	op.GeoM.Translate(float64(c.rect.Min.X), float64(c.rect.Min.Y))
   167  	screen.DrawImage(c.img, op)
   168  	return nil
   169  }
   170  

View as plain text