diff --git a/raymenu/go.mod b/raymenu/go.mod new file mode 100644 index 0000000..0d614bf --- /dev/null +++ b/raymenu/go.mod @@ -0,0 +1,15 @@ +module github.com/roodletoof/raymenu + +go 1.26.2 + +require ( + github.com/gen2brain/raylib-go/raygui v0.0.0-20260309161816-4c350487f71d + github.com/gen2brain/raylib-go/raylib v0.55.1 +) + +require ( + github.com/ebitengine/purego v0.10.0 // indirect + github.com/ktr0731/go-fuzzyfinder v0.9.0 // indirect + golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a // indirect + golang.org/x/sys v0.44.0 // indirect +) diff --git a/raymenu/go.sum b/raymenu/go.sum new file mode 100644 index 0000000..200ce68 --- /dev/null +++ b/raymenu/go.sum @@ -0,0 +1,12 @@ +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= +github.com/ktr0731/go-fuzzyfinder v0.9.0 h1:JV8S118RABzRl3Lh/RsPhXReJWc2q0rbuipzXQH7L4c= +github.com/ktr0731/go-fuzzyfinder v0.9.0/go.mod h1:uybx+5PZFCgMCSDHJDQ9M3nNKx/vccPmGffsXPn2ad8= +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/raymenu/gomono-font/GoMonoNerdFont-Bold.ttf b/raymenu/gomono-font/GoMonoNerdFont-Bold.ttf new file mode 100644 index 0000000..4883762 Binary files /dev/null and b/raymenu/gomono-font/GoMonoNerdFont-Bold.ttf differ diff --git a/raymenu/gomono-font/GoMonoNerdFont-BoldItalic.ttf b/raymenu/gomono-font/GoMonoNerdFont-BoldItalic.ttf new file mode 100644 index 0000000..2e24f9a Binary files /dev/null and b/raymenu/gomono-font/GoMonoNerdFont-BoldItalic.ttf differ diff --git a/raymenu/gomono-font/GoMonoNerdFont-Italic.ttf b/raymenu/gomono-font/GoMonoNerdFont-Italic.ttf new file mode 100644 index 0000000..0b0deb9 Binary files /dev/null and b/raymenu/gomono-font/GoMonoNerdFont-Italic.ttf differ diff --git a/raymenu/gomono-font/GoMonoNerdFont-Regular.ttf b/raymenu/gomono-font/GoMonoNerdFont-Regular.ttf new file mode 100644 index 0000000..16a642c Binary files /dev/null and b/raymenu/gomono-font/GoMonoNerdFont-Regular.ttf differ diff --git a/raymenu/gomono-font/GoMonoNerdFontMono-Bold.ttf b/raymenu/gomono-font/GoMonoNerdFontMono-Bold.ttf new file mode 100644 index 0000000..55ca751 Binary files /dev/null and b/raymenu/gomono-font/GoMonoNerdFontMono-Bold.ttf differ diff --git a/raymenu/gomono-font/GoMonoNerdFontMono-BoldItalic.ttf b/raymenu/gomono-font/GoMonoNerdFontMono-BoldItalic.ttf new file mode 100644 index 0000000..d27007a Binary files /dev/null and b/raymenu/gomono-font/GoMonoNerdFontMono-BoldItalic.ttf differ diff --git a/raymenu/gomono-font/GoMonoNerdFontMono-Italic.ttf b/raymenu/gomono-font/GoMonoNerdFontMono-Italic.ttf new file mode 100644 index 0000000..0be8766 Binary files /dev/null and b/raymenu/gomono-font/GoMonoNerdFontMono-Italic.ttf differ diff --git a/raymenu/gomono-font/GoMonoNerdFontMono-Regular.ttf b/raymenu/gomono-font/GoMonoNerdFontMono-Regular.ttf new file mode 100644 index 0000000..afbd8de Binary files /dev/null and b/raymenu/gomono-font/GoMonoNerdFontMono-Regular.ttf differ diff --git a/raymenu/gomono-font/GoMonoNerdFontPropo-Bold.ttf b/raymenu/gomono-font/GoMonoNerdFontPropo-Bold.ttf new file mode 100644 index 0000000..b96434b Binary files /dev/null and b/raymenu/gomono-font/GoMonoNerdFontPropo-Bold.ttf differ diff --git a/raymenu/gomono-font/GoMonoNerdFontPropo-BoldItalic.ttf b/raymenu/gomono-font/GoMonoNerdFontPropo-BoldItalic.ttf new file mode 100644 index 0000000..d4e8a19 Binary files /dev/null and b/raymenu/gomono-font/GoMonoNerdFontPropo-BoldItalic.ttf differ diff --git a/raymenu/gomono-font/GoMonoNerdFontPropo-Italic.ttf b/raymenu/gomono-font/GoMonoNerdFontPropo-Italic.ttf new file mode 100644 index 0000000..e9d59b2 Binary files /dev/null and b/raymenu/gomono-font/GoMonoNerdFontPropo-Italic.ttf differ diff --git a/raymenu/gomono-font/GoMonoNerdFontPropo-Regular.ttf b/raymenu/gomono-font/GoMonoNerdFontPropo-Regular.ttf new file mode 100644 index 0000000..0f0f2b2 Binary files /dev/null and b/raymenu/gomono-font/GoMonoNerdFontPropo-Regular.ttf differ diff --git a/raymenu/gomono-font/LICENSE.txt b/raymenu/gomono-font/LICENSE.txt new file mode 100644 index 0000000..7043c36 --- /dev/null +++ b/raymenu/gomono-font/LICENSE.txt @@ -0,0 +1,36 @@ +These fonts were created by the Bigelow & Holmes foundry specifically for the +Go project. See https://blog.golang.org/go-fonts for details. + +They are licensed under the same open source license as the rest of the Go +project's software: + +Copyright (c) 2016 Bigelow & Holmes Inc.. All rights reserved. + +Distribution of this font is governed by the following license. If you do not +agree to this license, including the disclaimer, do not distribute or modify +this font. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of Google Inc. nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +DISCLAIMER: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/raymenu/gomono-font/README.md b/raymenu/gomono-font/README.md new file mode 100644 index 0000000..0cbcdda --- /dev/null +++ b/raymenu/gomono-font/README.md @@ -0,0 +1,52 @@ +# Nerd Fonts + +This is an archived font from the Nerd Fonts release v3.4.0. + +For more information see: +* https://github.com/ryanoasis/nerd-fonts/ +* https://github.com/ryanoasis/nerd-fonts/releases/latest/ + +# Go Mono + +**Go** is a font created for the Go project. + +https://go.dev/blog/go-fonts + +For more information have a look at the upstream website: https://go.googlesource.com/image/ + +Download link https://go.googlesource.com/image/+/master/font/gofont/ttfs/ + +Version: 2.010 + +## Which font? + +### TL;DR + +* Pick your font family: + * If you are limited to monospaced fonts (because of your terminal, etc) then pick a font with `Nerd Font Mono` (or `NFM`). + * If you want to have bigger icons (usually around 1.5 normal letters wide) pick a font without `Mono` i.e. `Nerd Font` (or `NF`). Most terminals support this, but ymmv. + * If you work in a proportional context (GUI elements or edit a presentation etc) pick a font with `Nerd Font Propo` (or `NFP`). + +### Ligatures + +Ligatures are generally preserved in the patched fonts. +Nerd Fonts `v2.0.0` had no ligatures in the `Nerd Font Mono` fonts, this has been dropped with `v2.1.0`. +If you have a ligature-aware terminal and don't want ligatures you can (usually) disable them in the terminal settings. + +### Explanation + +Once you narrow down your font choice of family (`Droid Sans`, `Inconsolata`, etc) and style (`bold`, `italic`, etc) you have 2 main choices: + +#### `Option 1: Download already patched font` + + * For a stable version download a font package from the [release page](https://github.com/ryanoasis/nerd-fonts/releases) + * Or download the development version from the folders here + +#### `Option 2: Patch your own font` + + * Patch your own variations with the various options provided by the font patcher (i.e. not include all symbols for smaller font size) + +For more information see: [The FAQ](https://github.com/ryanoasis/nerd-fonts/wiki/FAQ-and-Troubleshooting#which-font) + +[SIL-RFN]:http://scripts.sil.org/cms/scripts/page.php?item_id=OFL_web_fonts_and_RFNs#14cbfd4a + diff --git a/raymenu/main.go b/raymenu/main.go new file mode 100644 index 0000000..44946e9 --- /dev/null +++ b/raymenu/main.go @@ -0,0 +1,188 @@ +package main + +import ( + "fmt" + "io" + "log" + "os" + "slices" + "strings" + + _ "embed" + + rg "github.com/gen2brain/raylib-go/raygui" + rl "github.com/gen2brain/raylib-go/raylib" + "github.com/ktr0731/go-fuzzyfinder/matching" +) + +//go:embed gomono-font/GoMonoNerdFontMono-Regular.ttf +var gomonoNerdFont_ttf []byte + +type State struct { + Font rl.Font +} + +func main() { + input, err := io.ReadAll(os.Stdin) + if err != nil { + log.Fatalln(err) + } + lines := strings.Split(string(input), "\n") + lines = slices.DeleteFunc(lines, func(l string) bool { + return l == "" + }) + choice, result := raymenu(lines) + switch (result) { + case RayMenuResult_NoChoice: + return + case RayMenuResult_Chosen: + fmt.Println(choice) + return + default: + log.Fatalln("Unhandled RayMenuResult", result) + } +} + +type RayMenuResult int + +const ( + RayMenuResult_NoChoice RayMenuResult = iota + RayMenuResult_Chosen + Count_RayMenuResult int = iota +) + +const width = 800 + +func isPressedRepeat(key int32) bool { + return rl.IsKeyPressed(key) || rl.IsKeyPressedRepeat(key) +} + +const fontSize = 14 + +func raymenu(options []string) (choice string, result RayMenuResult) { + state := initialize() + rg.SetFont(state.Font) + rg.SetStyle(rg.DEFAULT, rg.TEXT_SIZE, fontSize) + // TODO kinda dumb with additional initialization here + originalOrder := make([]matching.Matched, len(options)) + for i := range options { + originalOrder[i].Idx=i + } + cursor := 0 + matched := originalOrder + var prevInput string + var input string + for !rl.WindowShouldClose() { + rl.BeginDrawing() + rl.ClearBackground(rl.Black) + resetBounds() + bounds := nextBounds() + + isControlDown := rl.IsKeyDown(rl.KeyLeftControl) || rl.IsKeyDown(rl.KeyRightControl) + alternativeBackspace := isPressedRepeat(rl.KeyH) && isControlDown + enter := (rl.IsKeyPressed(rl.KeyY) && isControlDown) || + rl.IsKeyPressed(rl.KeyEnter) + + if alternativeBackspace && len(input) > 0 { + input = input[:len(input)-1] + } + + rg.TextBox(bounds, &input, 1024, true) + if prevInput != input { + if len(input) > 0 { + matched = matching.FindAll(input, options) + } else { + matched = originalOrder + } + cursor = 0 + prevInput = input + } + + { // cursor update + moveCursorUp := isPressedRepeat(rl.KeyP) && isControlDown + moveCursorDown := isPressedRepeat(rl.KeyN) && isControlDown + if moveCursorUp { + cursor -= 1 + } + if moveCursorDown { + cursor += 1 + } + if cursor >= len(matched) { + cursor = len(matched) - 1 + } + if cursor < 0 { + cursor = 0 + } + } + + if enter { + rl.EndDrawing() // TODO: dont need this? + rl.CloseWindow() + if cursor < len(matched) { + return options[matched[cursor].Idx], RayMenuResult_Chosen + } + return "", RayMenuResult_NoChoice + } + + for i, match := range matched { + bounds := nextBounds() + textBounds := bounds + textBounds.X += textBounds.Height + textBounds.Width -= textBounds.Height + rg.DrawText( + options[match.Idx], + textBounds, + int32(rg.TEXT_ALIGN_LEFT), + rl.White, + ) + + if i == cursor { + rl.DrawCircle( + int32(bounds.X)+int32(bounds.Height)/2, + int32(bounds.Y)+int32(bounds.Height)/2, + max(textBoxHeight / 8, 1), + rl.White, + ) + } + } + rl.EndDrawing() + } + + return "", RayMenuResult_NoChoice +} + +var yOffset float32 = 0.0 +const textBoxHeight = fontSize + 6 + +func resetBounds() { + yOffset = 0.0 +} + +func nextBounds() (bounds rl.Rectangle) { + bounds = rl.Rectangle{X: 0, Y: yOffset, Width: float32(rl.GetScreenWidth()), Height: textBoxHeight} + yOffset += textBoxHeight + return +} + +func initialize() State { + rl.SetTraceLogLevel(rl.LogError) + rl.InitWindow(width, 0, "raymenu") + rl.SetWindowState(rl.FlagWindowUndecorated) + rl.SetTargetFPS( + int32( + rl.GetMonitorRefreshRate( + rl.GetCurrentMonitor(), + ), + ), + ) + rl.SetWindowSize( + width, + rl.GetMonitorHeight( + rl.GetCurrentMonitor(), + ), + ) + + return State{ + Font: rl.LoadFontFromMemory(".ttf", gomonoNerdFont_ttf, fontSize, nil), + } +}