package main import ( "fmt" rl "github.com/gen2brain/raylib-go/raylib" ) // Keep your global variables for steps and transitions var ( transition = NewTransitionManager() currentStep = 0 targetStep = 0 useDefault = false step1DefaultRect rl.Rectangle step1CustomRect rl.Rectangle // Our global Installer from installer.go installer = NewInstaller() ) func main() { monitor := rl.GetCurrentMonitor() screenW := rl.GetMonitorWidth(monitor) screenH := rl.GetMonitorHeight(monitor) rl.InitWindow(int32(screenW), int32(screenH), "Spitfire Browser Installer") rl.SetWindowState(rl.FlagFullscreenMode) defer rl.CloseWindow() refreshRate := rl.GetMonitorRefreshRate(monitor) if refreshRate <= 0 { refreshRate = 60 // Fallback to 60 if detection fails } rl.SetTargetFPS(int32(refreshRate)) InitBackground(rl.GetScreenWidth(), rl.GetScreenHeight()) // Start the download+decompress in background immediately: installer.StartDownloadDecompress() targetStep = 0 for !rl.WindowShouldClose() { screenW = rl.GetScreenWidth() screenH = rl.GetScreenHeight() mousePos := rl.GetMousePosition() buttonW := 100 buttonH := 30 prevX := int32(50) prevY := int32(screenH - 50) nextX := int32(screenW - 150) nextY := prevY // Update transition oldAlpha, oldScale, oldOffsetX, newAlpha, newScale, newOffsetX := transition.Update() if !transition.IsActive() && currentStep != targetStep { currentStep = targetStep } // Poll SPM progress for the GUI installer.PollProgress() // If an unrecoverable error occurred, you could handle it here: // (For now, we just print it in the console.) if installer.LastError != nil { fmt.Println("SPM Error:", installer.LastError) // You might choose to show a popup or do something else } // GUI input if !transition.IsActive() && rl.IsMouseButtonPressed(rl.MouseLeftButton) { handleInput(mousePos, screenW, screenH, buttonW, buttonH, prevX, prevY, nextX, nextY) } UpdateBackground(screenW, screenH) rl.BeginDrawing() DrawBackground(screenW, screenH) drawHeader(screenW) oldStep := currentStep newStep := currentStep if transition.IsActive() { oldStep = transition.oldStep newStep = transition.newStep } phase := transition.GetPhase() if transition.IsActive() { if phase == TransitionOutFadeScale { drawStep(oldStep, screenW, screenH, mousePos, oldAlpha, oldScale, oldOffsetX) } else { drawStep(oldStep, screenW, screenH, mousePos, oldAlpha, oldScale, oldOffsetX) drawStep(newStep, screenW, screenH, mousePos, newAlpha, newScale, newOffsetX) } } else { drawStep(currentStep, screenW, screenH, mousePos, 1.0, 1.0, 0.0) } if !transition.IsActive() { if currentStep > 0 && currentStep < 3 { drawButton("Previous", prevX, prevY, int32(buttonW), int32(buttonH), mousePos) } if currentStep == 1 { drawButton("Next", nextX, nextY, int32(buttonW), int32(buttonH), mousePos) } else if currentStep == 2 { drawButton("Finish", nextX, nextY, int32(buttonW), int32(buttonH), mousePos) } } // Draw the semi-transparent loading circle if user is downloading or installing if installer.IsDownloading || installer.IsInstalling { drawInstallProgress(screenW, installer.Progress, installer.Task) } rl.EndDrawing() } } // handleInput acts on mouse clicks in each step func handleInput(mousePos rl.Vector2, screenW, screenH, buttonW, buttonH int, prevX, prevY, nextX, nextY int32) { if currentStep == 0 { if overRect(mousePos, step1DefaultRect) { // user clicked "Default" => do final install if not already installing useDefault = true if !installer.IsInstalling && !installer.DoneInstall { installer.FinalInstall() } fmt.Println("Installation started with default settings.") } if overRect(mousePos, step1CustomRect) { useDefault = false startTransition(currentStep, 1) } } else if currentStep == 1 { if overButton(mousePos, nextX, nextY, int32(buttonW), int32(buttonH)) { startTransition(currentStep, 2) } if overButton(mousePos, int32(prevX), int32(prevY), int32(buttonW), int32(buttonH)) { startTransition(currentStep, 0) } selectColor(mousePos) selectContrastIcon(mousePos) selectTheme(mousePos) } else if currentStep == 2 { if overButton(mousePos, nextX, nextY, int32(buttonW), int32(buttonH)) { // user clicked "Finish" => final install if not already installing if !installer.IsInstalling && !installer.DoneInstall { installer.FinalInstall() } fmt.Printf("Installation started:\nDefault: %v\nColor: %s\nTheme: %s\nLayout: %s\n", useDefault, selectedColor, selectedTheme, selectedLayout) } if overButton(mousePos, int32(prevX), int32(prevY), int32(buttonW), int32(buttonH)) { startTransition(currentStep, 1) } selectLayoutOption(mousePos) } } // drawHeader is your original function func drawHeader(screenW int) { title := "Spitfire Browser Installer" titleFontSize := int32(30) titleWidth := rl.MeasureText(title, titleFontSize) rl.DrawText(title, (int32(screenW)-titleWidth)/2, 20, titleFontSize, rl.RayWhite) rl.DrawLine(50, 60, int32(screenW)-50, 60, rl.Fade(rl.White, 0.5)) } // drawInstallProgress displays a simple white circle with partial alpha, // plus the current task text below it, in the top-right area. func drawInstallProgress(screenW int, progress int, task string) { circleX := float32(screenW - 80) circleY := float32(100) radius := float32(30) // Colors for the circle bgColor := rl.Color{R: 255, G: 255, B: 255, A: 80} fillColor := rl.Color{R: 255, G: 255, B: 255, A: 200} // Draw background circle rl.DrawCircle(int32(circleX), int32(circleY), radius, bgColor) // Draw progress arc angle := float32(progress) / 100.0 * 360.0 rl.DrawCircleSector( rl.Vector2{X: circleX, Y: circleY}, radius, 0, angle, 40, fillColor, ) // Print numeric progress txt := fmt.Sprintf("%3d%%", progress) rl.DrawText(txt, int32(circleX)-rl.MeasureText(txt, 18)/2, int32(circleY)-10, 18, rl.White) // Draw wrapped task text below the circle drawTextWrapped(task, int32(circleX)-100, int32(circleY)+40, 200, 18, rl.White) } // Custom function to draw text with wrapping func drawTextWrapped(text string, x, y int32, maxWidth, fontSize int32, color rl.Color) { words := splitIntoWords(text) line := "" offsetY := int32(0) for _, word := range words { testLine := line + word + " " if rl.MeasureText(testLine, fontSize) > int32(maxWidth) { rl.DrawText(line, x, y+offsetY, fontSize, color) line = word + " " offsetY += fontSize + 2 } else { line = testLine } } // Draw the last line if line != "" { rl.DrawText(line, x, y+offsetY, fontSize, color) } } // Helper function to split text into words func splitIntoWords(text string) []string { words := []string{} word := "" for _, char := range text { if char == ' ' || char == '\n' { if word != "" { words = append(words, word) word = "" } if char == '\n' { words = append(words, "\n") } } else { word += string(char) } } if word != "" { words = append(words, word) } return words } // startTransition is your existing function func startTransition(from, to int) { targetStep = to transition.Start(from, to) } // SPM example // package main // import ( // "fmt" // "os" // "path/filepath" // "spitfire-installer/spm" // "time" // ) // func main() { // // Start a goroutine to display progress updates // done := make(chan bool) // go func() { // for { // select { // case <-done: // return // default: // percentage, task := spm.GetProgress() // fmt.Printf("\r[%3d%%] %s", percentage, task) // time.Sleep(500 * time.Millisecond) // } // } // }() // // Set up the download directory // downloadDir := spm.GetTempDownloadDir() // fmt.Println("\nTemporary download directory:", downloadDir) // // Download the APPINDEX // appIndexPath := filepath.Join(downloadDir, "APPINDEX") // spm.UpdateProgress(0, "Starting APPINDEX download") // if err := spm.DownloadAppIndex(appIndexPath); err != nil { // fmt.Println("\nError downloading APPINDEX:", err) // done <- true // os.Exit(1) // } // // Download the desired package version (e.g., nightly) // packageName := "spitfire-browser" // release := "nightly" // spm.UpdateProgress(0, "Starting package download") // if err := spm.DownloadPackageFromAppIndex(appIndexPath, packageName, release, downloadDir); err != nil { // fmt.Println("\nError downloading package:", err) // done <- true // os.Exit(1) // } // // Decompress and install // packagePath := filepath.Join(downloadDir, "browser-amd64-nightly-linux.tar.gz") // spm.UpdateProgress(0, "Starting decompression") // tempDir, err := spm.DecompressToTemp(packagePath) // if err != nil { // fmt.Println("\nError decompressing package:", err) // done <- true // os.Exit(1) // } // fmt.Println("\nDecompressed package to:", tempDir) // installDir := "/home/czmisacz/Stažené/spitfire" // Change to your desired install directory // spm.UpdateProgress(0, "Starting installation") // if err := spm.MoveFilesToInstallDir(tempDir, installDir); err != nil { // fmt.Println("\nError installing package:", err) // done <- true // os.Exit(1) // } // // Notify progress display to stop and finalize // done <- true // fmt.Printf("\nSuccessfully installed %s (%s) to %s\n", packageName, release, installDir) // }