Noah Petherbridge
602273aa16
The Buttons can now be managed by a ui.Supervisor and be notified when the mouse enters or leaves their bounding box and handle click events. Current event handlers supported: * MouseOver * MouseOut * MouseDown * MouseUp * Click Each of those events are only fired when the state of the event has changed, i.e. the first time the mouse enters the widget MouseOver is called and then when the mouse leaves later, MouseOut is called. A completed click event (mouse was released while pressed and hovering the button) triggers both MouseOut and Click, so the button can pop itself out and also run the click handler.
227 lines
5.0 KiB
Go
227 lines
5.0 KiB
Go
// Package sdl provides an SDL2 renderer for Doodle.
|
|
package sdl
|
|
|
|
import (
|
|
"errors"
|
|
"time"
|
|
|
|
"git.kirsle.net/apps/doodle/events"
|
|
"git.kirsle.net/apps/doodle/render"
|
|
"github.com/veandco/go-sdl2/sdl"
|
|
"github.com/veandco/go-sdl2/ttf"
|
|
)
|
|
|
|
// Renderer manages the SDL state.
|
|
type Renderer struct {
|
|
// Configurable fields.
|
|
title string
|
|
width int32
|
|
height int32
|
|
startTime time.Time
|
|
|
|
// Private fields.
|
|
events *events.State
|
|
window *sdl.Window
|
|
renderer *sdl.Renderer
|
|
running bool
|
|
ticks uint64
|
|
|
|
// Optimizations to minimize SDL calls.
|
|
lastColor render.Color
|
|
}
|
|
|
|
// New creates the SDL renderer.
|
|
func New(title string, width, height int32) *Renderer {
|
|
return &Renderer{
|
|
events: events.New(),
|
|
title: title,
|
|
width: width,
|
|
height: height,
|
|
}
|
|
}
|
|
|
|
// Teardown tasks when exiting the program.
|
|
func (r *Renderer) Teardown() {
|
|
r.renderer.Destroy()
|
|
r.window.Destroy()
|
|
sdl.Quit()
|
|
}
|
|
|
|
// Setup the renderer.
|
|
func (r *Renderer) Setup() error {
|
|
// Initialize SDL.
|
|
log.Info("Initializing SDL")
|
|
if err := sdl.Init(sdl.INIT_EVERYTHING); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Initialize SDL_TTF.
|
|
log.Info("Initializing SDL_TTF")
|
|
if err := ttf.Init(); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Create our window.
|
|
log.Info("Creating the Main Window")
|
|
window, err := sdl.CreateWindow(
|
|
r.title,
|
|
sdl.WINDOWPOS_CENTERED,
|
|
sdl.WINDOWPOS_CENTERED,
|
|
r.width,
|
|
r.height,
|
|
sdl.WINDOW_SHOWN,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r.window = window
|
|
|
|
// Blank out the window in white.
|
|
log.Info("Creating the SDL Renderer")
|
|
renderer, err := sdl.CreateRenderer(window, -1, sdl.RENDERER_ACCELERATED)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
r.renderer = renderer
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetTicks gets SDL's current tick count.
|
|
func (r *Renderer) GetTicks() uint32 {
|
|
return sdl.GetTicks()
|
|
}
|
|
|
|
// Poll for events.
|
|
func (r *Renderer) Poll() (*events.State, error) {
|
|
s := r.events
|
|
for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
|
|
switch t := event.(type) {
|
|
case *sdl.QuitEvent:
|
|
return s, errors.New("quit")
|
|
case *sdl.MouseMotionEvent:
|
|
if DebugMouseEvents {
|
|
log.Debug("[%d ms] tick:%d MouseMotion type:%d id:%d x:%d y:%d xrel:%d yrel:%d",
|
|
t.Timestamp, r.ticks, t.Type, t.Which, t.X, t.Y, t.XRel, t.YRel,
|
|
)
|
|
}
|
|
|
|
// Push the cursor position.
|
|
s.CursorX.Push(t.X)
|
|
s.CursorY.Push(t.Y)
|
|
s.Button1.Push(t.State == 1)
|
|
case *sdl.MouseButtonEvent:
|
|
if DebugClickEvents {
|
|
log.Debug("[%d ms] tick:%d MouseButton type:%d id:%d x:%d y:%d button:%d state:%d",
|
|
t.Timestamp, r.ticks, t.Type, t.Which, t.X, t.Y, t.Button, t.State,
|
|
)
|
|
}
|
|
|
|
// Push the cursor position.
|
|
s.CursorX.Push(t.X)
|
|
s.CursorY.Push(t.Y)
|
|
|
|
// Is a mouse button pressed down?
|
|
if t.Button == 1 {
|
|
var eventName string
|
|
if t.State == 1 && s.Button1.Now == false {
|
|
eventName = "DOWN"
|
|
} else if t.State == 0 && s.Button1.Now == true {
|
|
eventName = "UP"
|
|
}
|
|
|
|
if eventName != "" {
|
|
log.Debug("tick:%d Mouse Button1 %s BEFORE: %+v",
|
|
r.ticks,
|
|
eventName,
|
|
s.Button1,
|
|
)
|
|
s.Button1.Push(eventName == "DOWN")
|
|
log.Debug("tick:%d Mouse Button1 %s AFTER: %+v",
|
|
r.ticks,
|
|
eventName,
|
|
s.Button1,
|
|
)
|
|
|
|
// Return the event immediately.
|
|
return s, nil
|
|
}
|
|
}
|
|
|
|
// s.Button2.Push(t.Button == 3 && t.State == 1)
|
|
case *sdl.MouseWheelEvent:
|
|
if DebugMouseEvents {
|
|
log.Debug("[%d ms] tick:%d MouseWheel type:%d id:%d x:%d y:%d",
|
|
t.Timestamp, r.ticks, t.Type, t.Which, t.X, t.Y,
|
|
)
|
|
}
|
|
case *sdl.KeyboardEvent:
|
|
if DebugKeyEvents {
|
|
log.Debug("[%d ms] tick:%d Keyboard type:%d sym:%c modifiers:%d state:%d repeat:%d\n",
|
|
t.Timestamp, r.ticks, t.Type, t.Keysym.Sym, t.Keysym.Mod, t.State, t.Repeat,
|
|
)
|
|
}
|
|
|
|
switch t.Keysym.Scancode {
|
|
case sdl.SCANCODE_ESCAPE:
|
|
if t.Repeat == 1 {
|
|
continue
|
|
}
|
|
s.EscapeKey.Push(t.State == 1)
|
|
case sdl.SCANCODE_RETURN:
|
|
if t.Repeat == 1 {
|
|
continue
|
|
}
|
|
s.EnterKey.Push(t.State == 1)
|
|
case sdl.SCANCODE_F12:
|
|
s.ScreenshotKey.Push(t.State == 1)
|
|
case sdl.SCANCODE_UP:
|
|
s.Up.Push(t.State == 1)
|
|
case sdl.SCANCODE_LEFT:
|
|
s.Left.Push(t.State == 1)
|
|
case sdl.SCANCODE_RIGHT:
|
|
s.Right.Push(t.State == 1)
|
|
case sdl.SCANCODE_DOWN:
|
|
s.Down.Push(t.State == 1)
|
|
case sdl.SCANCODE_LSHIFT:
|
|
case sdl.SCANCODE_RSHIFT:
|
|
s.ShiftActive.Push(t.State == 1)
|
|
continue
|
|
case sdl.SCANCODE_LALT:
|
|
case sdl.SCANCODE_RALT:
|
|
case sdl.SCANCODE_LCTRL:
|
|
case sdl.SCANCODE_RCTRL:
|
|
continue
|
|
case sdl.SCANCODE_BACKSPACE:
|
|
// Make it a key event with "\b" as the sequence.
|
|
if t.State == 1 || t.Repeat == 1 {
|
|
s.KeyName.Push(`\b`)
|
|
}
|
|
default:
|
|
// Push the string value of the key.
|
|
if t.State == 1 {
|
|
s.KeyName.Push(string(t.Keysym.Sym))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return s, nil
|
|
}
|
|
|
|
// Present the current frame.
|
|
func (r *Renderer) Present() error {
|
|
r.renderer.Present()
|
|
return nil
|
|
}
|
|
|
|
// Delay using sdl.Delay
|
|
func (r *Renderer) Delay(time uint32) {
|
|
sdl.Delay(time)
|
|
}
|
|
|
|
// Loop is the main loop.
|
|
func (r *Renderer) Loop() error {
|
|
return nil
|
|
}
|