203 lines
5.2 KiB
Go
203 lines
5.2 KiB
Go
package main
|
|
|
|
import (
|
|
"github.com/fogleman/gg"
|
|
//"github.com/shermp/go-fbink-v2/gofbink"
|
|
//"github.com/shermp/go-kobo-input/koboin"
|
|
"fmt"
|
|
"golang.org/x/image/font"
|
|
"image"
|
|
"strings"
|
|
)
|
|
|
|
var keyboardLowercase [][]string = [][]string{
|
|
{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "BKSP"},
|
|
{"q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "ENTER"},
|
|
{"a", "s", "d", "f", "g", "h", "j", "k", "l", "~", "SHIFT"},
|
|
{"z", "x", "c", "v", "b", "n", "m", ".", "/", ":", "SPACE"},
|
|
}
|
|
|
|
/*
|
|
var keyboardUppercase [][]string = [][]string{
|
|
{"!","\"","£","$","%","^","&","*","(",")","BKSP"},
|
|
{"Q","W","E","R","T","Y","U","I","O","P","ENTER"},
|
|
{"A","S","D","F","G","H","J","K","L","?","SHIFT"},
|
|
{"Z","X","C","V","B","N","M",",","<",">","SPACE"},
|
|
}
|
|
*/
|
|
|
|
// KeyLocation encodes a keyboard key and where it is on the screen, so input can be scanned.
|
|
type KeyLocation struct {
|
|
X, Y, W, H int
|
|
Label string
|
|
Keycode string
|
|
}
|
|
|
|
// Button records a button and where it is on screen so it can be pressed
|
|
type Button struct {
|
|
X, Y, W, H int
|
|
Label string
|
|
}
|
|
|
|
func touchingButton(x, y int, b Button) bool {
|
|
if x > b.X && x < b.X+b.W && y > b.Y && y < b.Y+b.H {
|
|
return true
|
|
} else {
|
|
return false
|
|
}
|
|
}
|
|
|
|
func touchingKey(x, y int, k KeyLocation) bool {
|
|
if x > k.X && x < k.X+k.W && y > k.Y && y < k.Y+k.H {
|
|
return true
|
|
} else {
|
|
return false
|
|
}
|
|
}
|
|
|
|
// Draws a simple dialog box
|
|
func drawDialog(text string, f *font.Face) {
|
|
boxheight := height / 4
|
|
boxwidth := width / 2
|
|
i := image.NewRGBA(image.Rect(0, 0, boxwidth, boxheight))
|
|
dc := gg.NewContextForRGBA(i)
|
|
if *f != nil {
|
|
dc.SetFontFace(*f)
|
|
}
|
|
dc.SetLineWidth(linewidth)
|
|
dc.DrawRectangle(0, 0, float64(boxwidth), float64(boxheight))
|
|
dc.SetRGB(1, 1, 1)
|
|
dc.FillPreserve()
|
|
dc.SetRGB(0, 0, 0)
|
|
dc.Stroke()
|
|
dc.SetRGB(0, 0, 0)
|
|
dc.DrawStringWrapped(text, float64(boxwidth/2), float64(boxheight/2), 0.5, 0.5, float64(boxwidth), 1.0, gg.AlignCenter)
|
|
dc.Fill()
|
|
fb.PrintRBGA(int16(width/2-(boxwidth/2)), int16(height/2-(boxheight/2)), i, &fbinkOpts)
|
|
|
|
}
|
|
|
|
func DrawTitleBar(f *font.Face) ([]Button, error) {
|
|
buttons := []Button{
|
|
Button{X: 0, Y: 0, W: width / 2, H: 100, Label: "Exit"},
|
|
Button{X: width / 2, Y: 0, W: width / 2, H: 100, Label: "Go"}}
|
|
i := image.NewRGBA(image.Rect(0, 0, width, titleBarHeight))
|
|
dc := gg.NewContextForRGBA(i)
|
|
if *f != nil {
|
|
dc.SetFontFace(*f)
|
|
}
|
|
dc.SetLineWidth(linewidth)
|
|
for _, b := range buttons {
|
|
dc.DrawRectangle(float64(b.X), float64(b.Y), float64(b.W), float64(b.H))
|
|
dc.SetRGB(1, 1, 1)
|
|
dc.FillPreserve()
|
|
dc.SetRGB(0, 0, 0)
|
|
dc.Stroke()
|
|
dc.DrawStringWrapped(b.Label, float64(b.X+b.W/2), float64(b.Y+b.H/2), 0.5, 0.5, float64(b.W), 1.0, gg.AlignCenter)
|
|
}
|
|
fb.PrintRBGA(0, 0, i, &fbinkOpts)
|
|
return buttons, nil
|
|
}
|
|
|
|
// GetInput draws an OSK and dialog then gets input from the user. It returns the inputted string and a potential error.
|
|
// TODO: more feedback to the user
|
|
func GetInput(f *font.Face, prompt string) (string, error) {
|
|
var s string
|
|
shifted := false
|
|
// Draw onscreen keyboard
|
|
board, err := drawOSK(f, keyboardLowercase)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
drawDialog(prompt+"\n ", f)
|
|
|
|
// Handle input
|
|
for {
|
|
x, y, err := t.GetInput()
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
continue
|
|
}
|
|
for _, key := range board {
|
|
if touchingKey(x, y, key) {
|
|
if key.Keycode == "ENTER" {
|
|
return s, nil
|
|
} else if key.Keycode == "BKSP" {
|
|
if len(s) >= 1 {
|
|
s = s[:len(s)-1]
|
|
}
|
|
} else if key.Keycode == "SHIFT" {
|
|
shifted = !shifted
|
|
//board, err = drawOSK(fb, opts, f, keyboardUppercase)
|
|
s = s + "^"
|
|
//if err != nil {
|
|
// return "", err
|
|
// }
|
|
} else if key.Keycode == "SPACE" {
|
|
s = s + " "
|
|
} else {
|
|
if shifted {
|
|
s = s[:len(s)-1]
|
|
s = s + strings.ToUpper(key.Keycode)
|
|
shifted = false
|
|
} else {
|
|
s = s + key.Keycode
|
|
}
|
|
}
|
|
drawDialog(prompt+"\n"+s, f)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// drawOSK draws an on-screen keyboard.
|
|
func drawOSK(f *font.Face, keyboard [][]string) ([]KeyLocation, error) {
|
|
var board []KeyLocation
|
|
var keysw int // Keys wide
|
|
keysh := len(keyboard) // Keys high
|
|
for _, r := range keyboard {
|
|
if len(r) > keysw {
|
|
keysw = len(r)
|
|
}
|
|
}
|
|
oskheight := height / 3
|
|
i := image.NewRGBA(image.Rect(0, 0, width, oskheight))
|
|
dc := gg.NewContextForRGBA(i)
|
|
if *f != nil {
|
|
dc.SetFontFace(*f)
|
|
}
|
|
dc.SetLineWidth(linewidth)
|
|
dc.DrawRectangle(0, 0, float64(width), float64(oskheight))
|
|
dc.SetRGB(1, 1, 1)
|
|
dc.FillPreserve()
|
|
dc.SetRGB(0, 0, 0)
|
|
dc.Stroke()
|
|
boardwidth := float64(width) - oskpadding*2
|
|
boardheight := float64(height/3) - oskpadding*2
|
|
keywidth := boardwidth / float64(keysw)
|
|
keyheight := boardheight / float64(keysh)
|
|
ypos := oskpadding
|
|
for _, r := range keyboard {
|
|
xpos := oskpadding // padding
|
|
for _, k := range r {
|
|
dc.DrawStringAnchored(k, xpos+keywidth/2, ypos+keyheight/2, 0.5, 0.5)
|
|
dc.Fill()
|
|
board = append(board, KeyLocation{X: int(xpos), Y: int(ypos) + (height/3)*2, W: int(keywidth), H: int(keyheight), Label: k, Keycode: k})
|
|
xpos += keywidth
|
|
}
|
|
ypos += keyheight
|
|
}
|
|
|
|
err := fb.PrintRBGA(0, int16(height-oskheight), i, &fbinkOpts)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return board, nil
|
|
}
|
|
|
|
// drawErrorBox prints the given error on screen, and only proceeds after touch input.
|
|
func drawErrorBox(e error, f *font.Face) {
|
|
drawDialog("Error:\n"+e.Error(), f)
|
|
t.GetInput()
|
|
}
|