From 48510db209ecae06444cd6465161c36f68df7d92 Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Sat, 12 Nov 2022 19:02:24 -0500 Subject: [PATCH] Added mouse button press input --- backends/x/x.go | 133 +++++++++++++++++++++--------------------- examples/draw/main.go | 65 +++++++++++++++++++++ input.go | 31 +++++----- 3 files changed, 150 insertions(+), 79 deletions(-) create mode 100644 examples/draw/main.go diff --git a/backends/x/x.go b/backends/x/x.go index f22eb0f..d3c6b47 100644 --- a/backends/x/x.go +++ b/backends/x/x.go @@ -1,6 +1,7 @@ package x import "os" +// import "fmt" import "sync" import "image" import "image/draw" @@ -9,7 +10,7 @@ import "golang.org/x/image/math/fixed" import "golang.org/x/image/font/opentype" import "golang.org/x/image/font/basicfont" -import "github.com/jezek/xgb" +// import "github.com/jezek/xgb" import "github.com/jezek/xgbutil" import "github.com/jezek/xgb/xproto" import "github.com/jezek/xgbutil/ewmh" @@ -31,12 +32,6 @@ type Backend struct { drawLock sync.Mutex - ping struct { - before chan(struct { }) - after chan(struct { }) - quit chan(struct { }) - } - font struct { face font.Face } @@ -62,30 +57,8 @@ type Backend struct { func (backend *Backend) Run (channel chan(stone.Event)) { backend.channel = channel - - for { - select { - case <- backend.ping.before: - // if the queue is empty, don't dequeue anything because - // it would cause a fucking segfault lmao (???) - if !xevent.Empty(backend.connection) { - event, err := xevent.Dequeue(backend.connection) - if err != nil { - // TODO: do something with err - } - - if event != nil { - backend.handleXEvent(event) - } - } - - <- backend.ping.after - - case <- backend.ping.quit: - backend.shutDown() - return - } - } + xevent.Main(backend.connection) + backend.shutDown() } func (backend *Backend) Draw () { @@ -104,10 +77,6 @@ func (backend *Backend) Draw () { backend.canvas.XDraw() backend.canvas.XPaint(backend.window.Id) } else { - // backend.drawCells(false) - // backend.canvas.XDraw() - // backend.canvas.XPaint(backend.window.Id) - // FIXME use this instead once it works backend.updateWindowAreas(backend.drawCells(false)...) } } @@ -154,28 +123,44 @@ func (backend *Backend) SetIcon (icons []image.Image) (err error) { return } -func (backend *Backend) handleXEvent (event xgb.Event) { - switch event.(type) { - case xproto.ConfigureNotifyEvent: - configureEvent := event.(xproto.ConfigureNotifyEvent) - - newWidth := int(configureEvent.Width) - newHeight := int(configureEvent.Height) - sizeChanged := - backend.metrics.windowWidth != newWidth || - backend.metrics.windowHeight != newHeight - backend.metrics.windowWidth = newWidth - backend.metrics.windowHeight = newHeight +func (backend *Backend) handleConfigureNotify ( + connection *xgbutil.XUtil, + event xevent.ConfigureNotifyEvent, +) { + configureEvent := *event.ConfigureNotifyEvent + + newWidth := int(configureEvent.Width) + newHeight := int(configureEvent.Height) + sizeChanged := + backend.metrics.windowWidth != newWidth || + backend.metrics.windowHeight != newHeight + backend.metrics.windowWidth = newWidth + backend.metrics.windowHeight = newHeight - if sizeChanged { - configureEvent = - backend.compressConfigureNotify(configureEvent) - backend.application.SetSize(backend.calculateBufferSize()) - backend.channel <- stone.EventResize { } - } + if sizeChanged { + configureEvent = + backend.compressConfigureNotify(configureEvent) + backend.application.SetSize(backend.calculateBufferSize()) + backend.channel <- stone.EventResize { } } } +func (backend *Backend) handleButtonPress ( + connection *xgbutil.XUtil, + event xevent.ButtonPressEvent, +) { + buttonEvent := *event.ButtonPressEvent + backend.channel <- stone.EventPress(buttonEvent.Detail) +} + +func (backend *Backend) handleButtonRelease ( + connection *xgbutil.XUtil, + event xevent.ButtonReleaseEvent, +) { + buttonEvent := *event.ButtonReleaseEvent + backend.channel <- stone.EventRelease(buttonEvent.Detail) +} + func (backend *Backend) compressConfigureNotify ( firstEvent xproto.ConfigureNotifyEvent, ) ( @@ -253,7 +238,8 @@ func (backend *Backend) drawCells (forceRedraw bool) (areas []image.Rectangle) { cell := backend.application.Cell(x, y) content := cell.Rune() - if content < 32 { continue } + + if forceRedraw && content < 32 { continue } areas = append(areas, backend.boundsOfCell(x, y)) backend.drawRune(x, y, content) @@ -269,6 +255,16 @@ func (backend *Backend) drawRune (x, y int, character rune) { // TODO: cache these draws as non-transparent buffers with the // application background color as the background. that way, we won't // need to redraw the characters *or* composite them. + + fillRectangle ( + &image.Uniform { + C: backend.config.Color(stone.ColorApplication), + }, + backend.canvas, + backend.boundsOfCell(x, y)) + + if character < 32 { return } + origin := backend.originOfCell(x, y + 1) destinationRectangle, mask, maskPoint, _, _ := backend.font.face.Glyph ( fixed.Point26_6 { @@ -277,13 +273,6 @@ func (backend *Backend) drawRune (x, y int, character rune) { }, character) - fillRectangle ( - &image.Uniform { - C: backend.config.Color(stone.ColorApplication), - }, - backend.canvas, - backend.boundsOfCell(x, y)) - // strokeRectangle ( // &image.Uniform { // C: backend.config.Color(stone.ColorForeground), @@ -382,7 +371,16 @@ func factory (application *stone.Application) (output stone.Backend, err error) backend.metrics.windowWidth, backend.metrics.windowHeight, 0) backend.window.Map() - backend.window.Listen(xproto.EventMaskStructureNotify) + // TODO: also listen to mouse movement (compressed) and mouse and + // keyboard buttons (uncompressed) + err = backend.window.Listen ( + xproto.EventMaskStructureNotify, + // xproto.EventMaskPointerMotion, + // xproto.EventMaskKeyPress, + // xproto.EventMaskKeyRelease, + xproto.EventMaskButtonPress, + xproto.EventMaskButtonRelease, + ) backend.SetTitle(application.Title()) backend.SetIcon(application.Icon()) @@ -395,10 +393,13 @@ func factory (application *stone.Application) (output stone.Backend, err error) backend.shutDown() }) - // start event loop - backend.ping.before, - backend.ping.after, - backend.ping.quit = xevent.MainPing(backend.connection) + // attatch event handlers + xevent.ConfigureNotifyFun(backend.handleConfigureNotify). + Connect(backend.connection, backend.window.Id) + xevent.ButtonPressFun(backend.handleButtonPress). + Connect(backend.connection, backend.window.Id) + xevent.ButtonReleaseFun(backend.handleButtonRelease). + Connect(backend.connection, backend.window.Id) output = backend return diff --git a/examples/draw/main.go b/examples/draw/main.go new file mode 100644 index 0000000..5aca10c --- /dev/null +++ b/examples/draw/main.go @@ -0,0 +1,65 @@ +package main + +import "os" +import "image" +import _ "image/png" +import "git.tebibyte.media/sashakoshka/stone" +import _ "git.tebibyte.media/sashakoshka/stone/backends/x" + +var application = &stone.Application { } +var mousePressed bool + +func main () { + application.SetTitle("hellorld") + application.SetSize(32, 16) + + iconFile16, err := os.Open("assets/scaffold16.png") + if err != nil { panic(err) } + icon16, _, err := image.Decode(iconFile16) + if err != nil { panic(err) } + iconFile16.Close() + iconFile32, err := os.Open("assets/scaffold32.png") + if err != nil { panic(err) } + icon32, _, err := image.Decode(iconFile32) + if err != nil { panic(err) } + iconFile16.Close() + + application.SetIcon([]image.Image { icon16, icon32 }) + + channel, err := application.Run() + if err != nil { panic(err) } + + application.Draw() + + for { + event := <- channel + switch event.(type) { + case stone.EventQuit: + os.Exit(0) + + case stone.EventPress: + event := event.(stone.EventPress) + if stone.Button(event) == stone.MouseButtonLeft { + mousePressed = true + application.SetRune(0, 0, '+') + application.Draw() + } + + case stone.EventRelease: + event := event.(stone.EventRelease) + if stone.Button(event) == stone.MouseButtonLeft { + mousePressed = false + application.SetRune(0, 0, 0) + application.Draw() + } + + case stone.EventMouseMove: + event := event.(stone.EventMouseMove) + application.SetRune(event.X, event.Y, '#') + application.Draw() + + case stone.EventResize: + application.Draw() + } + } +} diff --git a/input.go b/input.go index 694a234..c76118b 100644 --- a/input.go +++ b/input.go @@ -1,7 +1,5 @@ package stone -// These should be identical to the glfw keys - type Button int const ( @@ -129,15 +127,22 @@ const ( KeyRightSuper Button = 257 KeyMenu Button = 256 - MouseButton1 Button = 0 - MouseButton2 Button = 1 - MouseButton3 Button = 2 - MouseButton4 Button = 3 - MouseButton5 Button = 4 - MouseButton6 Button = 5 - MouseButton7 Button = 6 - MouseButton8 Button = 7 - MouseButtonLeft Button = MouseButton1 - MouseButtonRight Button = MouseButton2 - MouseButtonMiddle Button = MouseButton3 + MouseButton1 Button = 1 + MouseButton2 Button = 2 + MouseButton3 Button = 3 + MouseButton4 Button = 4 + MouseButton5 Button = 5 + MouseButton6 Button = 6 + MouseButton7 Button = 7 + MouseButton8 Button = 8 + MouseButton9 Button = 9 + MouseButtonLeft Button = MouseButton1 + MouseButtonMiddle Button = MouseButton2 + MouseButtonRight Button = MouseButton3 + MouseButtonScrollUp Button = MouseButton4 + MouseButtonScrollDown Button = MouseButton5 + MouseButtonScrollLeft Button = MouseButton6 + MouseButtonScrollRight Button = MouseButton7 + MouseButtonBack Button = MouseButton8 + MouseButtonForward Button = MouseButton9 )