diff --git a/main.go b/main.go index 034ec6e..df3e2b8 100644 --- a/main.go +++ b/main.go @@ -23,7 +23,7 @@ var ( hosts tofu.KnownHosts hostsfile *tofu.HostWriter scanner *bufio.Scanner - face font.Face + uiFace font.Face fbinkOpts gofbink.FBInkConfig fb *gofbink.FBInk f *truetype.Font @@ -32,11 +32,12 @@ var ( // Visual options const ( - width int = 1080 - height int = 1440 // TODO get from device instead of hardcoding - linewidth float64 = 5 - oskpadding float64 = 20 - keyspacing float64 = 5 // spacing between keys + width int = 1080 + height int = 1440 // TODO get from device instead of hardcoding + linewidth float64 = 5 + oskpadding float64 = 20 + keyspacing float64 = 5 // spacing between keys + titleBarHeight int = height / 6 ) func trustCertificate(hostname string, cert *x509.Certificate) error { @@ -67,7 +68,7 @@ func do(req *gemini.Request, via []*gemini.Request) (*gemini.Response, error) { switch resp.Status.Class() { case gemini.StatusClassInput: // TODO sensitive input - input, err := GetInput(&face, resp.Meta+":") + input, err := GetInput(&uiFace, resp.Meta+":") if err != nil { break } @@ -94,6 +95,29 @@ func do(req *gemini.Request, via []*gemini.Request) (*gemini.Response, error) { return resp, err } +func getPage(u *url.URL) (string, error) { + req, err := gemini.NewRequest(u.String()) + if err != nil { + return "", nil + } + resp, err := do(req, nil) + if err != nil { + return "", nil + } + defer resp.Body.Close() + + // Handle response + if resp.Status.Class() == gemini.StatusClassSuccess { + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + return string(body), nil + } else { + return "", errors.New(fmt.Sprintf("%s %s", string(resp.Status), string(resp.Meta))) + } +} + func main() { // Framebuffer setup fbinkOpts = gofbink.FBInkConfig{} @@ -113,7 +137,7 @@ func main() { // Logging setup var logFile, err = os.Create("/mnt/onboard/gemini.log") if err != nil { - drawErrorBox(err, &face) + drawErrorBox(err, &uiFace) } var logger *log.Logger = log.New(logFile, "gemini", log.LstdFlags) defer logFile.Close() @@ -126,7 +150,7 @@ func main() { } err = hosts.Load(path) if err != nil { - drawErrorBox(err, &face) + drawErrorBox(err, &uiFace) logger.Fatal(err) } @@ -147,53 +171,45 @@ func main() { logger.Println(err) return } - face = truetype.NewFace(f, &truetype.Options{Size: 32}) + uiFace = truetype.NewFace(f, &truetype.Options{Size: 32}) - str, err := GetInput(&face, "Test:") + titleBarButtons, err := DrawTitleBar(&uiFace) if err != nil { - fb.Println("Error: ") + drawErrorBox(err, &uiFace) logger.Fatal(err) } - - u, err := url.Parse(str) - if err != nil { - drawErrorBox(err, &face) - logger.Println(err) - } - if u.Scheme == "" { - u.Scheme = "gemini" - } - fmt.Println(u.String()) - - req, err := gemini.NewRequest(u.String()) - if err != nil { - drawErrorBox(err, &face) - logger.Fatal(err) - } - resp, err := do(req, nil) - if err != nil { - drawErrorBox(err, &face) - logger.Fatal(err) - } - defer resp.Body.Close() - - // Handle response - if resp.Status.Class() == gemini.StatusClassSuccess { - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - drawErrorBox(err, &face) - logger.Fatal(err) - } - fb.ClearScreen(&fbinkOpts) - fb.Println(string(body)) - fmt.Println(string(body)) - } else { - fb.Println(fmt.Sprintf("%d %s\n", resp.Status, resp.Meta)) - } + for { x, y, _ := t.GetInput() - if x < 100 && y < 100 { - break + for _, b := range titleBarButtons { + if touchingButton(x, y, b) { + if b.Label == "Exit" { + return + } else if b.Label == "Go" { + str, err := GetInput(&uiFace, "Enter URL:") + if err != nil { + drawErrorBox(err, &uiFace) + logger.Println(err) + } + u, err := url.Parse(str) + if err != nil { + drawErrorBox(err, &uiFace) + logger.Println(err) + } + if u.Scheme == "" { + u.Scheme = "gemini" + } + content, err := getPage(u) + if err != nil { + drawErrorBox(err, &uiFace) + logger.Println(err) + } else { + fb.Println(content) // TODO rendering, not this! Also links + } + + + } + } } } hostsfile.Close() diff --git a/ui.go b/ui.go index 874a9d5..9df68d4 100644 --- a/ui.go +++ b/ui.go @@ -33,6 +33,20 @@ type KeyLocation struct { 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 @@ -63,6 +77,28 @@ func drawDialog(text string, f *font.Face) { } +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) {