super basic GUI in raylib, use x11/xwayland forced mode and bruteforce scaling because the GLFW devs don't know how to support wayland

This commit is contained in:
2026-05-12 02:19:37 -05:00
commit b04a1810dd
3 changed files with 165 additions and 0 deletions
+11
View File
@@ -0,0 +1,11 @@
module github.com/wisplite/astargo
go 1.25.6
require (
github.com/ebitengine/purego v0.10.0 // indirect
github.com/gen2brain/raylib-go/raygui v0.0.0-20260309161816-4c350487f71d // indirect
github.com/gen2brain/raylib-go/raylib v0.55.1 // indirect
golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a // indirect
golang.org/x/sys v0.44.0 // indirect
)
+10
View File
@@ -0,0 +1,10 @@
github.com/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ISU=
github.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/gen2brain/raylib-go/raygui v0.0.0-20260309161816-4c350487f71d h1:os8MZA0q9yHNk2KQVFepMhtukfC9QLBubBoxN3hKxAk=
github.com/gen2brain/raylib-go/raygui v0.0.0-20260309161816-4c350487f71d/go.mod h1:Don7nFrETwG1JBACDZPvRahYPaSSvhLY9v9NUzD1YWc=
github.com/gen2brain/raylib-go/raylib v0.55.1 h1:1rdc10WvvYjtj7qijHnV9T38/WuvlT6IIL+PaZ6cNA8=
github.com/gen2brain/raylib-go/raylib v0.55.1/go.mod h1:BaY76bZk7nw1/kVOSQObPY1v1iwVE1KHAGMfvI6oK1Q=
golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a h1:+3jdDGGB8NGb1Zktc737jlt3/A5f6UlwSzmvqUuufxw=
golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a/go.mod h1:d2fgXJLVs4dYDHUk5lwMIfzRzSrWCfGZb0ZqeLa/Vcw=
golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
+144
View File
@@ -0,0 +1,144 @@
package main
import (
"strconv"
rg "github.com/gen2brain/raylib-go/raygui"
rl "github.com/gen2brain/raylib-go/raylib"
)
func canvasMouse() rl.Vector2 {
return rl.GetMousePosition()
}
func drawGrid(grid [][]int, lineThickness float32) {
if lineThickness > 5 {
lineThickness = 0
}
for i := 0; i < len(grid); i++ {
for j := 0; j < len(grid[i]); j++ {
rl.DrawRectangle(int32(i*25), int32(j*25), 25, 25, rl.NewColor(240, 240, 240, 255))
if lineThickness > 0 {
rl.DrawRectangleLinesEx(rl.NewRectangle(float32(i*25), float32(j*25), 25, 25), lineThickness, rl.Black)
}
}
}
}
func generateGrid(width int, height int) [][]int {
grid := make([][]int, width)
for i := range grid {
grid[i] = make([]int, height)
}
return grid
}
func main() {
rl.SetConfigFlags(rl.FlagWindowResizable)
rl.InitWindow(int32(800), int32(450), "Raylib - Wayland Safe Zoom & Resize")
defer rl.CloseWindow()
scale := rl.GetWindowScaleDPI().X
if scale == 0 {
scale = 2.0 // Fallback value
}
rg.SetStyle(rg.DEFAULT, rg.TEXT_SIZE, rg.PropertyValue(int64(10*scale)))
rl.SetTargetFPS(60)
// Keep offset safely at 0,0. We will never modify this during runtime.
camera := rl.Camera2D{
Offset: rl.NewVector2(0, 0),
Target: rl.NewVector2(0, 0),
Rotation: 0.0,
Zoom: 1.0,
}
width := 10
height := 10
widthInputValue := "10"
heightInputValue := "10"
editModeWidth := false
editModeHeight := false
grid := generateGrid(width, height)
for !rl.WindowShouldClose() {
screenWidth := float32(rl.GetScreenWidth())
screenHeight := float32(rl.GetScreenHeight())
sidebarWidth := float32(200) * scale
if sidebarWidth > screenWidth {
sidebarWidth = screenWidth
}
canvasWidth := screenWidth - sidebarWidth
wheel := rl.GetMouseWheelMove()
// --- THE BULLETPROOF ZOOM MATH ---
if wheel != 0 {
mousePos := canvasMouse()
// 1. Where is the mouse in the world BEFORE zooming?
worldPosBefore := rl.GetScreenToWorld2D(mousePos, camera)
// 2. Apply the zoom
camera.Zoom += float32(wheel) * 0.1
if camera.Zoom < 0.1 {
camera.Zoom = 0.1
}
// 3. Where does that same screen pixel point to AFTER zooming?
worldPosAfter := rl.GetScreenToWorld2D(mousePos, camera)
// 4. Shift the camera target to compensate for the difference
camera.Target.X += (worldPosBefore.X - worldPosAfter.X)
camera.Target.Y += (worldPosBefore.Y - worldPosAfter.Y)
}
// Move the camera with the right mouse button
if rl.IsMouseButtonDown(rl.MouseRightButton) {
delta := rl.GetMouseDelta()
camera.Target.X -= delta.X / camera.Zoom
camera.Target.Y -= delta.Y / camera.Zoom
}
// --- DRAWING ---
rl.BeginDrawing()
rl.ClearBackground(rl.White)
// 1. Draw Canvas
rl.BeginScissorMode(0, 0, int32(canvasWidth), int32(screenHeight))
rl.BeginMode2D(camera)
drawGrid(grid, 1/camera.Zoom)
rl.EndMode2D()
rl.EndScissorMode()
// 2. Draw Sidebar UI
sidebarX := canvasWidth
rl.DrawRectangleRec(rl.NewRectangle(sidebarX, 0, sidebarWidth, screenHeight), rl.RayWhite)
if rg.TextBox(rl.NewRectangle(sidebarX+(10*scale), (10*scale), (80*scale), (20*scale)), &widthInputValue, 20, editModeWidth) {
editModeWidth = !editModeWidth
if editModeWidth {
editModeHeight = false
}
}
rg.Label(rl.NewRectangle(sidebarX+(95*scale), (10*scale), (10*scale), (20*scale)), "x")
if rg.TextBox(rl.NewRectangle(sidebarX+(110*scale), (10*scale), (80*scale), (20*scale)), &heightInputValue, 20, editModeHeight) {
editModeHeight = !editModeHeight
if editModeHeight {
editModeWidth = false
}
}
if rg.Button(rl.NewRectangle(sidebarX+(10*scale), (40*scale), (180*scale), (30*scale)), "Generate Grid") {
width, _ = strconv.Atoi(widthInputValue)
height, _ = strconv.Atoi(heightInputValue)
grid = generateGrid(width, height)
}
rl.EndDrawing()
}
}