| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- // Copyright 2016 The G3N Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package gui
- import (
- "github.com/g3n/engine/window"
- )
- /***************************************
- Button Panel
- +-------------------------------+
- | Image/Icon Label |
- | +----------+ +----------+ |
- | | | | | |
- | | | | | |
- | +----------+ +----------+ |
- +-------------------------------+
- ****************************************/
- // Button represents a button GUI element
- type Button struct {
- *Panel // Embedded Panel
- Label *Label // Label panel
- image *Image // pointer to button image (may be nil)
- icon *Label // pointer to button icon (may be nil
- styles *ButtonStyles // pointer to current button styles
- mouseOver bool // true if mouse is over button
- pressed bool // true if button is pressed
- }
- // Button style
- type ButtonStyle BasicStyle
- // All Button styles
- type ButtonStyles struct {
- Normal ButtonStyle
- Over ButtonStyle
- Focus ButtonStyle
- Pressed ButtonStyle
- Disabled ButtonStyle
- }
- // NewButton creates and returns a pointer to a new button widget
- // with the specified text for the button label.
- func NewButton(text string) *Button {
- b := new(Button)
- b.styles = &StyleDefault().Button
- // Initializes the button panel
- b.Panel = NewPanel(0, 0)
- // Subscribe to panel events
- b.Subscribe(OnKeyDown, b.onKey)
- b.Subscribe(OnKeyUp, b.onKey)
- b.Subscribe(OnMouseUp, b.onMouse)
- b.Subscribe(OnMouseDown, b.onMouse)
- b.Subscribe(OnCursor, b.onCursor)
- b.Subscribe(OnCursorEnter, b.onCursor)
- b.Subscribe(OnCursorLeave, b.onCursor)
- b.Subscribe(OnEnable, func(name string, ev interface{}) { b.update() })
- b.Subscribe(OnResize, func(name string, ev interface{}) { b.recalc() })
- // Creates label
- b.Label = NewLabel(text)
- b.Label.Subscribe(OnResize, func(name string, ev interface{}) { b.recalc() })
- b.Panel.Add(b.Label)
- b.recalc() // recalc first then update!
- b.update()
- return b
- }
- // SetIcon sets the button icon from the default Icon font.
- // If there is currently a selected image, it is removed
- func (b *Button) SetIcon(icode string) {
- ico := NewIcon(icode)
- if b.image != nil {
- b.Panel.Remove(b.image)
- b.image = nil
- }
- if b.icon != nil {
- b.Panel.Remove(b.icon)
- }
- b.icon = ico
- b.icon.SetFontSize(b.Label.FontSize() * 1.4)
- b.Panel.Add(b.icon)
- b.recalc()
- b.update()
- }
- // SetImage sets the button left image from the specified filename
- // If there is currently a selected icon, it is removed
- func (b *Button) SetImage(imgfile string) error {
- img, err := NewImage(imgfile)
- if err != nil {
- return err
- }
- if b.image != nil {
- b.Panel.Remove(b.image)
- }
- b.image = img
- b.Panel.Add(b.image)
- b.recalc()
- return nil
- }
- // SetStyles set the button styles overriding the default style
- func (b *Button) SetStyles(bs *ButtonStyles) {
- b.styles = bs
- b.update()
- }
- // onCursor process subscribed cursor events
- func (b *Button) onCursor(evname string, ev interface{}) {
- switch evname {
- case OnCursorEnter:
- b.mouseOver = true
- b.update()
- case OnCursorLeave:
- b.pressed = false
- b.mouseOver = false
- b.update()
- }
- b.root.StopPropagation(StopAll)
- }
- // onMouseEvent process subscribed mouse events
- func (b *Button) onMouse(evname string, ev interface{}) {
- switch evname {
- case OnMouseDown:
- b.root.SetKeyFocus(b)
- b.pressed = true
- b.update()
- b.Dispatch(OnClick, nil)
- case OnMouseUp:
- b.pressed = false
- b.update()
- default:
- return
- }
- b.root.StopPropagation(StopAll)
- }
- // onKey processes subscribed key events
- func (b *Button) onKey(evname string, ev interface{}) {
- kev := ev.(*window.KeyEvent)
- if evname == OnKeyDown && kev.Keycode == window.KeyEnter {
- b.pressed = true
- b.update()
- b.Dispatch(OnClick, nil)
- b.root.StopPropagation(Stop3D)
- return
- }
- if evname == OnKeyUp && kev.Keycode == window.KeyEnter {
- b.pressed = false
- b.update()
- b.root.StopPropagation(Stop3D)
- return
- }
- return
- }
- // update updates the button visual state
- func (b *Button) update() {
- if !b.Enabled() {
- b.applyStyle(&b.styles.Disabled)
- return
- }
- if b.pressed {
- b.applyStyle(&b.styles.Pressed)
- return
- }
- if b.mouseOver {
- b.applyStyle(&b.styles.Over)
- return
- }
- b.applyStyle(&b.styles.Normal)
- }
- // applyStyle applies the specified button style
- func (b *Button) applyStyle(bs *ButtonStyle) {
- b.Panel.ApplyStyle(&bs.PanelStyle)
- if b.icon != nil {
- b.icon.SetColor4(&bs.FgColor)
- }
- b.Label.SetColor4(&bs.FgColor)
- }
- // recalc recalculates all dimensions and position from inside out
- func (b *Button) recalc() {
- // Current width and height of button content area
- width := b.Panel.ContentWidth()
- height := b.Panel.ContentHeight()
- // Image or icon width
- imgWidth := float32(0)
- spacing := float32(4)
- if b.image != nil {
- imgWidth = b.image.Width()
- } else if b.icon != nil {
- imgWidth = b.icon.Width()
- }
- if imgWidth == 0 {
- spacing = 0
- }
- // If the label is empty and an icon of image was defined ignore the label widthh
- // to centralize the icon/image in the button
- labelWidth := spacing + b.Label.Width()
- if b.Label.Text() == "" && imgWidth > 0 {
- labelWidth = 0
- }
- // Sets new content width and height if necessary
- minWidth := imgWidth + labelWidth
- minHeight := b.Label.Height()
- resize := false
- if width < minWidth {
- width = minWidth
- resize = true
- }
- if height < minHeight {
- height = minHeight
- resize = true
- }
- if resize {
- b.SetContentSize(width, height)
- }
- // Centralize horizontally
- px := (width - minWidth) / 2
- // Set label position
- ly := (height - b.Label.Height()) / 2
- b.Label.SetPosition(px+imgWidth+spacing, ly)
- // Image/icon position
- if b.image != nil {
- iy := (height - b.image.height) / 2
- b.image.SetPosition(px, iy)
- } else if b.icon != nil {
- b.icon.SetPosition(px, ly)
- }
- }
|