...

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

Documentation: code.rocket9labs.com/tslocum/etk

     1  package etk
     2  
     3  import (
     4  	"image"
     5  	"image/color"
     6  
     7  	"code.rocket9labs.com/tslocum/etk/messeji"
     8  	"github.com/hajimehoshi/ebiten/v2"
     9  	"github.com/hajimehoshi/ebiten/v2/text/v2"
    10  )
    11  
    12  // Button is a clickable button.
    13  type Button struct {
    14  	*Box
    15  	field         *messeji.TextField
    16  	btnBackground color.RGBA
    17  	textFont      *text.GoTextFaceSource
    18  	textSize      int
    19  	borderSize    int
    20  	borderTop     color.RGBA
    21  	borderRight   color.RGBA
    22  	borderBottom  color.RGBA
    23  	borderLeft    color.RGBA
    24  	onSelected    func() error
    25  	pressed       bool
    26  }
    27  
    28  // NewButton returns a new Button widget.
    29  func NewButton(label string, onSelected func() error) *Button {
    30  	textColor := Style.ButtonTextColor
    31  	if textColor.A == 0 {
    32  		textColor = Style.TextColorDark
    33  	}
    34  	f := newText()
    35  	f.SetText(label)
    36  	f.SetForegroundColor(textColor)
    37  	f.SetHorizontal(messeji.AlignCenter)
    38  	f.SetVertical(messeji.AlignCenter)
    39  	f.SetAutoResize(true)
    40  
    41  	b := &Button{
    42  		Box:           NewBox(),
    43  		field:         f,
    44  		btnBackground: Style.ButtonBgColor,
    45  		textFont:      Style.TextFont,
    46  		textSize:      Scale(Style.TextSize),
    47  		onSelected:    onSelected,
    48  		borderSize:    Scale(Style.ButtonBorderSize),
    49  		borderTop:     Style.ButtonBorderTop,
    50  		borderRight:   Style.ButtonBorderRight,
    51  		borderBottom:  Style.ButtonBorderBottom,
    52  		borderLeft:    Style.ButtonBorderLeft,
    53  	}
    54  	b.SetBackground(Style.ButtonBgColor)
    55  	return b
    56  }
    57  
    58  // SetRect sets the position and size of the Button.
    59  func (b *Button) SetRect(r image.Rectangle) {
    60  	b.Box.rect = r
    61  
    62  	b.field.SetRect(r)
    63  
    64  	for _, w := range b.children {
    65  		w.SetRect(r)
    66  	}
    67  }
    68  
    69  // SetBorderSize sets the size of the border around the button.
    70  func (b *Button) SetBorderSize(size int) {
    71  	b.Lock()
    72  	defer b.Unlock()
    73  
    74  	b.borderSize = size
    75  }
    76  
    77  // SetBorderColors sets the color of the top, right, bottom and left border.
    78  func (b *Button) SetBorderColors(top color.RGBA, right color.RGBA, bottom color.RGBA, left color.RGBA) {
    79  	b.Lock()
    80  	defer b.Unlock()
    81  
    82  	b.borderTop = top
    83  	b.borderRight = right
    84  	b.borderBottom = bottom
    85  	b.borderLeft = left
    86  }
    87  
    88  // SetForeground sets the color of the button label.
    89  func (b *Button) SetForeground(c color.RGBA) {
    90  	b.Lock()
    91  	defer b.Unlock()
    92  
    93  	b.field.SetForegroundColor(c)
    94  }
    95  
    96  // SetBackground sets the background color of the button label.
    97  func (b *Button) SetBackground(background color.RGBA) {
    98  	b.Lock()
    99  	defer b.Unlock()
   100  
   101  	b.btnBackground = background
   102  	b.background = background
   103  }
   104  
   105  // Text returns the content of the text buffer.
   106  func (b *Button) Text() string {
   107  	b.Lock()
   108  	defer b.Unlock()
   109  
   110  	return b.field.Text()
   111  }
   112  
   113  // SetText sets the text in the field.
   114  func (b *Button) SetText(text string) {
   115  	b.Lock()
   116  	defer b.Unlock()
   117  
   118  	b.field.SetText(text)
   119  }
   120  
   121  // SetFont sets the font and text size of button label. Scaling is not applied.
   122  func (b *Button) SetFont(fnt *text.GoTextFaceSource, size int) {
   123  	b.Lock()
   124  	defer b.Unlock()
   125  
   126  	b.textFont, b.textSize = fnt, size
   127  	b.field.SetFont(b.textFont, b.textSize, fontMutex)
   128  }
   129  
   130  // SetHorizontal sets the horizontal alignment of the button label.
   131  func (b *Button) SetHorizontal(h Alignment) {
   132  	b.Lock()
   133  	defer b.Unlock()
   134  
   135  	b.field.SetHorizontal(messeji.Alignment(h))
   136  }
   137  
   138  // SetVertical sets the vertical alignment of the button label.
   139  func (b *Button) SetVertical(v Alignment) {
   140  	b.Lock()
   141  	defer b.Unlock()
   142  
   143  	b.field.SetVertical(messeji.Alignment(v))
   144  }
   145  
   146  // Cursor returns the cursor shape shown when a mouse cursor hovers over the
   147  // widget, or -1 to let widgets beneath determine the cursor shape.
   148  func (b *Button) Cursor() ebiten.CursorShapeType {
   149  	return ebiten.CursorShapePointer
   150  }
   151  
   152  // HandleKeyboard is called when a keyboard event occurs.
   153  func (b *Button) HandleKeyboard(ebiten.Key, rune) (handled bool, err error) {
   154  	return false, nil
   155  }
   156  
   157  // HandleMouse is called when a mouse event occurs.
   158  func (b *Button) HandleMouse(cursor image.Point, pressed bool, clicked bool) (handled bool, err error) {
   159  	if !clicked {
   160  		if b.pressed && !pressed {
   161  			b.Lock()
   162  			b.pressed = false
   163  			b.background = b.btnBackground
   164  			b.Unlock()
   165  		}
   166  		return true, nil
   167  	}
   168  
   169  	const dim = 0.9
   170  	b.Lock()
   171  	b.pressed = true
   172  	b.background = color.RGBA{uint8(float64(b.btnBackground.R) * dim), uint8(float64(b.btnBackground.G) * dim), uint8(float64(b.btnBackground.B) * dim), 255}
   173  	onSelected := b.onSelected
   174  	if onSelected == nil {
   175  		b.Unlock()
   176  		return true, nil
   177  	}
   178  	b.Unlock()
   179  
   180  	return true, onSelected()
   181  }
   182  
   183  // Draw draws the button on the screen.
   184  func (b *Button) Draw(screen *ebiten.Image) error {
   185  	r := b.rect
   186  
   187  	// Draw label.
   188  	b.field.Draw(screen)
   189  
   190  	// Draw border.
   191  	if b.borderSize != 0 {
   192  		if !b.pressed {
   193  			screen.SubImage(image.Rect(r.Min.X, r.Min.Y, r.Min.X+b.borderSize, r.Max.Y)).(*ebiten.Image).Fill(b.borderLeft)
   194  			screen.SubImage(image.Rect(r.Min.X, r.Min.Y, r.Max.X, r.Min.Y+b.borderSize)).(*ebiten.Image).Fill(b.borderTop)
   195  			screen.SubImage(image.Rect(r.Max.X-b.borderSize, r.Min.Y, r.Max.X, r.Max.Y)).(*ebiten.Image).Fill(b.borderRight)
   196  			screen.SubImage(image.Rect(r.Min.X, r.Max.Y-b.borderSize, r.Max.X, r.Max.Y)).(*ebiten.Image).Fill(b.borderBottom)
   197  		} else {
   198  			screen.SubImage(image.Rect(r.Max.X-b.borderSize, r.Min.Y, r.Max.X, r.Max.Y)).(*ebiten.Image).Fill(b.borderLeft)
   199  			screen.SubImage(image.Rect(r.Min.X, r.Max.Y-b.borderSize, r.Max.X, r.Max.Y)).(*ebiten.Image).Fill(b.borderTop)
   200  			screen.SubImage(image.Rect(r.Min.X, r.Min.Y, r.Min.X+b.borderSize, r.Max.Y)).(*ebiten.Image).Fill(b.borderRight)
   201  			screen.SubImage(image.Rect(r.Min.X, r.Min.Y, r.Max.X, r.Min.Y+b.borderSize)).(*ebiten.Image).Fill(b.borderBottom)
   202  		}
   203  	}
   204  
   205  	return nil
   206  }
   207  

View as plain text