This repository has been archived on 2021-02-14. You can view files and clone it, but cannot push or open issues or pull requests.
kobo-gemini/ui.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()
}