193 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			193 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package elements
 | |
| 
 | |
| import "image"
 | |
| import "git.tebibyte.media/sashakoshka/tomo"
 | |
| import "git.tebibyte.media/sashakoshka/tomo/input"
 | |
| import "git.tebibyte.media/sashakoshka/tomo/textdraw"
 | |
| import "git.tebibyte.media/sashakoshka/tomo/elements/core"
 | |
| import "git.tebibyte.media/sashakoshka/tomo/default/theme"
 | |
| import "git.tebibyte.media/sashakoshka/tomo/default/config"
 | |
| 
 | |
| // Checkbox is a toggle-able checkbox with a label.
 | |
| type Checkbox struct {
 | |
| 	*core.Core
 | |
| 	*core.FocusableCore
 | |
| 	core core.CoreControl
 | |
| 	focusableControl core.FocusableCoreControl
 | |
| 	drawer textdraw.Drawer
 | |
| 
 | |
| 	pressed bool
 | |
| 	checked bool
 | |
| 	text    string
 | |
| 	
 | |
| 	config config.Wrapped
 | |
| 	theme  theme.Wrapped
 | |
| 	
 | |
| 	onToggle func ()
 | |
| }
 | |
| 
 | |
| // NewCheckbox creates a new cbeckbox with the specified label text.
 | |
| func NewCheckbox (text string, checked bool) (element *Checkbox) {
 | |
| 	element = &Checkbox { checked: checked }
 | |
| 	element.theme.Case = tomo.C("tomo", "checkbox")
 | |
| 	element.Core, element.core = core.NewCore(element, element.draw)
 | |
| 	element.FocusableCore,
 | |
| 	element.focusableControl = core.NewFocusableCore(element.core, element.redo)
 | |
| 	element.drawer.SetFace (element.theme.FontFace (
 | |
| 		tomo.FontStyleRegular,
 | |
| 		tomo.FontSizeNormal))
 | |
| 	element.SetText(text)
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (element *Checkbox) HandleMouseDown (x, y int, button input.Button) {
 | |
| 	if !element.Enabled() { return }
 | |
| 	element.Focus()
 | |
| 	element.pressed = true
 | |
| 	if element.core.HasImage() {
 | |
| 		element.draw()
 | |
| 		element.core.DamageAll()
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (element *Checkbox) HandleMouseUp (x, y int, button input.Button) {
 | |
| 	if button != input.ButtonLeft || !element.pressed { return }
 | |
| 
 | |
| 	element.pressed = false
 | |
| 	within := image.Point { x, y }.
 | |
| 		In(element.Bounds())
 | |
| 	if within {
 | |
| 		element.checked = !element.checked
 | |
| 	}
 | |
| 	
 | |
| 	if element.core.HasImage() {
 | |
| 		element.draw()
 | |
| 		element.core.DamageAll()
 | |
| 	}
 | |
| 	if within && element.onToggle != nil {
 | |
| 		element.onToggle()
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (element *Checkbox) HandleKeyDown (key input.Key, modifiers input.Modifiers) {
 | |
| 	if key == input.KeyEnter {
 | |
| 		element.pressed = true
 | |
| 		if element.core.HasImage() {
 | |
| 			element.draw()
 | |
| 			element.core.DamageAll()
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (element *Checkbox) HandleKeyUp (key input.Key, modifiers input.Modifiers) {
 | |
| 	if key == input.KeyEnter && element.pressed {
 | |
| 		element.pressed = false
 | |
| 		element.checked = !element.checked
 | |
| 		if element.core.HasImage() {
 | |
| 			element.draw()
 | |
| 			element.core.DamageAll()
 | |
| 		}
 | |
| 		if element.onToggle != nil {
 | |
| 			element.onToggle()
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // OnToggle sets the function to be called when the checkbox is toggled.
 | |
| func (element *Checkbox) OnToggle (callback func ()) {
 | |
| 	element.onToggle = callback
 | |
| }
 | |
| 
 | |
| // Value reports whether or not the checkbox is currently checked.
 | |
| func (element *Checkbox) Value () (checked bool) {
 | |
| 	return element.checked
 | |
| }
 | |
| 
 | |
| // SetEnabled sets whether this checkbox can be toggled or not.
 | |
| func (element *Checkbox) SetEnabled (enabled bool) {
 | |
| 	element.focusableControl.SetEnabled(enabled)
 | |
| }
 | |
| 
 | |
| // SetText sets the checkbox's label text.
 | |
| func (element *Checkbox) SetText (text string) {
 | |
| 	if element.text == text { return }
 | |
| 
 | |
| 	element.text = text
 | |
| 	element.drawer.SetText([]rune(text))
 | |
| 	element.updateMinimumSize()
 | |
| 	
 | |
| 	if element.core.HasImage () {
 | |
| 		element.draw()
 | |
| 		element.core.DamageAll()
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // SetTheme sets the element's theme.
 | |
| func (element *Checkbox) SetTheme (new tomo.Theme) {
 | |
| 	if new == element.theme.Theme { return }
 | |
| 	element.theme.Theme = new
 | |
| 	element.drawer.SetFace (element.theme.FontFace (
 | |
| 		tomo.FontStyleRegular,
 | |
| 		tomo.FontSizeNormal))
 | |
| 	element.updateMinimumSize()
 | |
| 	element.redo()
 | |
| }
 | |
| 
 | |
| // SetConfig sets the element's configuration.
 | |
| func (element *Checkbox) SetConfig (new tomo.Config) {
 | |
| 	if new == element.config.Config { return }
 | |
| 	element.config.Config = new
 | |
| 	element.updateMinimumSize()
 | |
| 	element.redo()
 | |
| }
 | |
| 
 | |
| func (element *Checkbox) updateMinimumSize () {
 | |
| 	textBounds := element.drawer.LayoutBounds()
 | |
| 	if element.text == "" {
 | |
| 		element.core.SetMinimumSize(textBounds.Dy(), textBounds.Dy())
 | |
| 	} else {
 | |
| 		margin := element.theme.Margin(tomo.PatternBackground)
 | |
| 		element.core.SetMinimumSize (
 | |
| 			textBounds.Dy() + margin.X + textBounds.Dx(),
 | |
| 			textBounds.Dy())
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (element *Checkbox) redo () {
 | |
| 	if element.core.HasImage () {
 | |
| 		element.draw()
 | |
| 		element.core.DamageAll()
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (element *Checkbox) draw () {
 | |
| 	bounds := element.Bounds()
 | |
| 	boxBounds := image.Rect(0, 0, bounds.Dy(), bounds.Dy()).Add(bounds.Min)
 | |
| 
 | |
| 	state := tomo.State {
 | |
| 		Disabled: !element.Enabled(),
 | |
| 		Focused:  element.Focused(),
 | |
| 		Pressed:  element.pressed,
 | |
| 		On:       element.checked,
 | |
| 	}
 | |
| 
 | |
| 	backgroundPattern := element.theme.Pattern (
 | |
| 		tomo.PatternBackground, state)
 | |
| 	backgroundPattern.Draw(element.core, bounds)
 | |
| 
 | |
| 	pattern := element.theme.Pattern(tomo.PatternButton, state)
 | |
| 	pattern.Draw(element.core, boxBounds)
 | |
| 
 | |
| 	textBounds := element.drawer.LayoutBounds()
 | |
| 	margin := element.theme.Margin(tomo.PatternBackground)
 | |
| 	offset := bounds.Min.Add(image.Point {
 | |
| 		X: bounds.Dy() + margin.X,
 | |
| 	})
 | |
| 
 | |
| 	offset.Y -= textBounds.Min.Y
 | |
| 	offset.X -= textBounds.Min.X
 | |
| 
 | |
| 	foreground := element.theme.Color(tomo.ColorForeground, state)
 | |
| 	element.drawer.Draw(element.core, foreground, offset)
 | |
| }
 |