From b04a1810dd8158d8045e645c2c9bc68f3049f90c Mon Sep 17 00:00:00 2001 From: wisplite Date: Tue, 12 May 2026 02:19:37 -0500 Subject: [PATCH] super basic GUI in raylib, use x11/xwayland forced mode and bruteforce scaling because the GLFW devs don't know how to support wayland --- go.mod | 11 +++++ go.sum | 10 ++++ main.go | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 165 insertions(+) create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..c7e9180 --- /dev/null +++ b/go.mod @@ -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 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..f55cfa1 --- /dev/null +++ b/go.sum @@ -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= diff --git a/main.go b/main.go new file mode 100644 index 0000000..ac57269 --- /dev/null +++ b/main.go @@ -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() + } +}