| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 |
- // 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"
- )
- /***************************************
- Slider
- +--------------------------------+
- | +--------------------------+ |
- | | +----------+ | |
- | | | | | |
- | | | | | |
- | | +----------+ | |
- | +--------------------------+ |
- +--------------------------------+
- **/
- // Slider is the GUI element for sliders and progress bars
- type Slider struct {
- Panel // Embedded panel
- slider Panel // embedded slider panel
- label *Label // optional label
- horiz bool // orientation
- styles *SliderStyles // pointer to styles
- pos float32 // current slider position
- posLast float32 // last position of the mouse cursor when dragging
- pressed bool // mouse button is pressed and dragging
- cursorOver bool // mouse is over slider
- scaleFactor float32 // scale factor (default = 1.0)
- }
- // SliderStyle contains the styling of a Slider
- type SliderStyle BasicStyle
- // SliderStyles contains a SliderStyle for each valid GUI state
- type SliderStyles struct {
- Normal SliderStyle
- Over SliderStyle
- Focus SliderStyle
- Disabled SliderStyle
- }
- // NewHSlider creates and returns a pointer to a new horizontal slider
- // with the specified initial dimensions.
- func NewHSlider(width, height float32) *Slider {
- return newSlider(true, width, height)
- }
- // NewVSlider creates and returns a pointer to a new vertical slider
- // with the specified initial dimensions.
- func NewVSlider(width, height float32) *Slider {
- return newSlider(false, width, height)
- }
- // NewSlider creates and returns a pointer to a new slider with the
- // specified initial dimensions.
- func newSlider(horiz bool, width, height float32) *Slider {
- s := new(Slider)
- s.horiz = horiz
- s.styles = &StyleDefault().Slider
- s.scaleFactor = 1.0
- // Initialize main panel
- s.Panel.Initialize(width, height)
- s.Panel.Subscribe(OnMouseDown, s.onMouse)
- s.Panel.Subscribe(OnMouseUp, s.onMouse)
- s.Panel.Subscribe(OnCursor, s.onCursor)
- s.Panel.Subscribe(OnCursorEnter, s.onCursor)
- s.Panel.Subscribe(OnCursorLeave, s.onCursor)
- s.Panel.Subscribe(OnScroll, s.onScroll)
- s.Panel.Subscribe(OnKeyDown, s.onKey)
- s.Panel.Subscribe(OnKeyRepeat, s.onKey)
- s.Panel.Subscribe(OnResize, s.onResize)
- s.Panel.Subscribe(OnEnable, func(evname string, ev interface{}) { s.update() })
- // Initialize slider panel
- s.slider.Initialize(0, 0)
- s.Panel.Add(&s.slider)
- s.recalc()
- s.update()
- return s
- }
- // SetStyles set the slider styles overriding the default style
- func (s *Slider) SetStyles(ss *SliderStyles) {
- s.styles = ss
- s.update()
- }
- // SetText sets the text of the slider optional label
- func (s *Slider) SetText(text string) {
- if s.label == nil {
- s.label = NewLabel(text)
- s.Panel.Add(s.label)
- } else {
- s.label.SetText(text)
- }
- s.update()
- s.recalc()
- }
- // SetValue sets the value of the slider considering the current scale factor
- // and updates its visual appearance.
- func (s *Slider) SetValue(value float32) {
- pos := value / s.scaleFactor
- s.setPos(pos)
- }
- // Value returns the current value of the slider considering the current scale factor
- func (s *Slider) Value() float32 {
- return s.pos * s.scaleFactor
- }
- // SetScaleFactor set the slider scale factor (default = 1.0)
- func (s *Slider) SetScaleFactor(factor float32) {
- s.scaleFactor = factor
- }
- // ScaleFactor returns the slider current scale factor (default = 1.0)
- func (s *Slider) ScaleFactor() float32 {
- return s.scaleFactor
- }
- // setPos sets the slider position from 0.0 to 1.0
- // and updates its visual appearance.
- func (s *Slider) setPos(pos float32) {
- const eps = 0.01
- if pos < 0 {
- pos = 0
- } else if pos > 1.0 {
- pos = 1
- }
- if pos > (s.pos+eps) && pos < (s.pos+eps) {
- return
- }
- s.pos = pos
- s.recalc()
- s.Dispatch(OnChange, nil)
- }
- // onMouse process subscribed mouse events over the outer panel
- func (s *Slider) onMouse(evname string, ev interface{}) {
- mev := ev.(*window.MouseEvent)
- switch evname {
- case OnMouseDown:
- s.pressed = true
- if s.horiz {
- s.posLast = mev.Xpos
- } else {
- s.posLast = mev.Ypos
- }
- s.root.SetMouseFocus(s)
- s.root.SetKeyFocus(s)
- case OnMouseUp:
- s.pressed = false
- if !s.cursorOver {
- s.root.SetCursorNormal()
- }
- s.root.SetMouseFocus(nil)
- default:
- return
- }
- s.root.StopPropagation(Stop3D)
- }
- // onCursor process subscribed cursor events
- func (s *Slider) onCursor(evname string, ev interface{}) {
- if evname == OnCursorEnter {
- s.root.SetScrollFocus(s)
- if s.horiz {
- s.root.SetCursorHResize()
- } else {
- s.root.SetCursorVResize()
- }
- s.cursorOver = true
- s.update()
- } else if evname == OnCursorLeave {
- s.root.SetScrollFocus(nil)
- s.root.SetCursorNormal()
- s.cursorOver = false
- s.update()
- } else if evname == OnCursor {
- if !s.pressed {
- return
- }
- cev := ev.(*window.CursorEvent)
- var pos float32
- if s.horiz {
- delta := cev.Xpos - s.posLast
- s.posLast = cev.Xpos
- newpos := s.slider.Width() + delta
- pos = newpos / s.Panel.ContentWidth()
- } else {
- delta := cev.Ypos - s.posLast
- s.posLast = cev.Ypos
- newpos := s.slider.Height() - delta
- pos = newpos / s.Panel.ContentHeight()
- }
- s.setPos(pos)
- }
- s.root.StopPropagation(Stop3D)
- }
- // onScroll process subscribed scroll events
- func (s *Slider) onScroll(evname string, ev interface{}) {
- sev := ev.(*window.ScrollEvent)
- v := s.pos
- v += sev.Yoffset * 0.01
- s.setPos(v)
- s.root.StopPropagation(Stop3D)
- }
- // onKey process subscribed key events
- func (s *Slider) onKey(evname string, ev interface{}) {
- kev := ev.(*window.KeyEvent)
- delta := float32(0.01)
- // Horizontal slider
- if s.horiz {
- switch kev.Keycode {
- case window.KeyLeft:
- s.setPos(s.pos - delta)
- case window.KeyRight:
- s.setPos(s.pos + delta)
- default:
- return
- }
- // Vertical slider
- } else {
- switch kev.Keycode {
- case window.KeyDown:
- s.setPos(s.pos - delta)
- case window.KeyUp:
- s.setPos(s.pos + delta)
- default:
- return
- }
- }
- s.root.StopPropagation(Stop3D)
- }
- // onResize process subscribed resize events
- func (s *Slider) onResize(evname string, ev interface{}) {
- s.recalc()
- }
- // update updates the slider visual state
- func (s *Slider) update() {
- if !s.Enabled() {
- s.applyStyle(&s.styles.Disabled)
- return
- }
- if s.cursorOver {
- s.applyStyle(&s.styles.Over)
- return
- }
- s.applyStyle(&s.styles.Normal)
- }
- // applyStyle applies the specified slider style
- func (s *Slider) applyStyle(ss *SliderStyle) {
- s.Panel.ApplyStyle(&ss.PanelStyle)
- s.slider.SetColor4(&ss.FgColor)
- }
- // recalc recalculates the dimensions and positions of the internal panels.
- func (s *Slider) recalc() {
- if s.horiz {
- if s.label != nil {
- lx := (s.Panel.ContentWidth() - s.label.Width()) / 2
- if s.Panel.ContentHeight() < s.label.Height() {
- s.Panel.SetContentHeight(s.label.Height())
- }
- ly := (s.Panel.ContentHeight() - s.label.Height()) / 2
- s.label.SetPosition(lx, ly)
- }
- width := s.Panel.ContentWidth() * s.pos
- s.slider.SetSize(width, s.Panel.ContentHeight())
- } else {
- if s.label != nil {
- if s.Panel.ContentWidth() < s.label.Width() {
- s.Panel.SetContentWidth(s.label.Width())
- }
- lx := (s.Panel.ContentWidth() - s.label.Width()) / 2
- ly := (s.Panel.ContentHeight() - s.label.Height()) / 2
- s.label.SetPosition(lx, ly)
- }
- height := s.Panel.ContentHeight() * s.pos
- s.slider.SetPositionY(s.Panel.ContentHeight() - height)
- s.slider.SetSize(s.Panel.ContentWidth(), height)
- }
- }
|