136 lines
3.1 KiB
Go
136 lines
3.1 KiB
Go
package widgets
|
|
|
|
import (
|
|
"fmt"
|
|
"image/color"
|
|
|
|
"tetris/engine/core"
|
|
"tetris/engine/input"
|
|
"tetris/engine/render"
|
|
"tetris/game/ui/base"
|
|
|
|
rl "github.com/gen2brain/raylib-go/raylib"
|
|
)
|
|
|
|
const (
|
|
sliderBorderSize = 4
|
|
sliderWidth = 200
|
|
sliderHeight = 30
|
|
sliderTextSize = 12
|
|
sliderTextOffset = 6
|
|
)
|
|
|
|
type SliderOnChange func(this *Slider)
|
|
|
|
type Slider struct {
|
|
*base.WithFocus
|
|
Min int
|
|
Max int
|
|
Step int
|
|
Value int
|
|
borderSize int32
|
|
onChange SliderOnChange
|
|
}
|
|
|
|
func NewSlider(min, max, step int) *Slider {
|
|
return &Slider{
|
|
WithFocus: &base.WithFocus{},
|
|
Min: min,
|
|
Max: max,
|
|
Step: step,
|
|
borderSize: 4,
|
|
}
|
|
}
|
|
|
|
func (slider *Slider) WithOnChange(callback SliderOnChange) *Slider {
|
|
slider.onChange = callback
|
|
return slider
|
|
}
|
|
|
|
func (slider Slider) Size() core.Vec2i {
|
|
w := sliderWidth + (sliderBorderSize * 2)
|
|
return core.Vec2i{
|
|
X: w + sliderTextOffset + (sliderTextSize * len(slider.ValueText())),
|
|
Y: sliderHeight + (sliderBorderSize * 2),
|
|
}
|
|
}
|
|
|
|
func (slider *Slider) HandleInput() {
|
|
if input.KeyPressedWithRepeat(rl.KeyLeft) {
|
|
slider.Decrement()
|
|
} else if input.KeyPressedWithRepeat(rl.KeyRight) {
|
|
slider.Increment()
|
|
}
|
|
}
|
|
|
|
func (slider *Slider) SetValue(value int) {
|
|
if value != slider.Value {
|
|
slider.Value = value
|
|
slider.onChange(slider)
|
|
}
|
|
}
|
|
|
|
func (slider *Slider) Increment() {
|
|
slider.SetValue(min(slider.Max, slider.Value+slider.Step))
|
|
}
|
|
|
|
func (slider *Slider) Decrement() {
|
|
slider.SetValue(max(slider.Min, slider.Value-slider.Step))
|
|
}
|
|
|
|
func (slider Slider) Percent() float32 {
|
|
return float32(slider.Min+slider.Value) / float32(slider.Max)
|
|
}
|
|
|
|
func (slider Slider) drawTrack(rect rl.RectangleInt32) {
|
|
spacing := int32(2)
|
|
num_marks := int32(10)
|
|
mark_width := float32(rect.Width-((num_marks+1)*spacing)) / float32(num_marks)
|
|
|
|
markRect := rl.Rectangle{
|
|
X: float32(rect.X + spacing),
|
|
Y: float32(rect.Y + spacing),
|
|
Width: mark_width,
|
|
Height: float32(rect.Height - (spacing * 2)),
|
|
}
|
|
|
|
for range num_marks {
|
|
rl.DrawRectangleRec(markRect, rl.DarkGray)
|
|
markRect.X += mark_width + float32(spacing)
|
|
}
|
|
}
|
|
|
|
func (slider Slider) drawHandle(x, y, width int32, height int32, col color.RGBA) {
|
|
handleWidth := int32(10)
|
|
x = x + int32(float32(width-handleWidth-2)*slider.Percent())
|
|
rl.DrawRectangle(x, y, handleWidth, height, col)
|
|
}
|
|
|
|
func (slider Slider) ValueText() string {
|
|
return fmt.Sprintf("%d", int(slider.Percent()*100))
|
|
}
|
|
|
|
func (slider Slider) Draw(x, y int32) {
|
|
// rl.DrawRectangle(x, y, int32(slider.Size().X), int32(slider.Size().Y), rl.Green)
|
|
|
|
// TODO: use a theme system here so colors are not hardcoded.
|
|
handleColor := rl.White
|
|
if slider.HasFocus() {
|
|
handleColor = rl.Red
|
|
}
|
|
|
|
rect := rl.RectangleInt32{
|
|
X: x + sliderBorderSize,
|
|
Y: y + sliderBorderSize,
|
|
Width: sliderWidth,
|
|
Height: sliderHeight,
|
|
}
|
|
|
|
render.DrawRectOutlineBorder(rect, slider.borderSize, handleColor)
|
|
slider.drawTrack(rect)
|
|
slider.drawHandle(rect.X+1, rect.Y+1, int32(rect.Width), sliderHeight-2, handleColor)
|
|
|
|
textOffset := x + int32(rect.Width) + (sliderBorderSize * 2) + sliderTextOffset
|
|
|
|
render.DrawText(textOffset, rect.Y+8, sliderTextSize, slider.ValueText(), rl.White)
|
|
}
|