summaryrefslogtreecommitdiff
path: root/cmd/rescribe/gui.go
blob: 654d875bf25973b3f79af1d92502e2e17b7610eb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// Copyright 2021 Nick White.
// Use of this source code is governed by the GPLv3
// license that can be found in the LICENSE file.

package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/dialog"
	"fyne.io/fyne/v2/layout"
	"fyne.io/fyne/v2/theme"
	"fyne.io/fyne/v2/widget"
)

// copyStdoutToChan creates a pipe to copy anything written
// to stdout instead to a rune channel
func copyStdoutToChan() (chan rune, error) {
	c := make(chan rune)

	origStdout := os.Stdout
	r, w, err := os.Pipe()
	if err != nil {
		return c, fmt.Errorf("Error creating pipe for stdout redirection: %v", err)
	}
	os.Stdout = w

	bufReader := bufio.NewReader(r)

	go func() {
		defer func() {
			close(c)
			w.Close()
			os.Stdout = origStdout
		}()
		for {
			r, _, err := bufReader.ReadRune()
			if err != nil && err != io.EOF {
				return
			}
			c <- r
			if err == io.EOF {
				return
			}
		}
	}()

	return c, nil
}

// startGui starts the gui process
func startGui(log log.Logger, cmd string, training string, systess bool, tessdir string) error {
	myApp := app.New()
	myWindow := myApp.NewWindow("Rescribe OCR")

	var gobtn *widget.Button

	dir := widget.NewEntry()
	dir.SetPlaceHolder("Folder to process")
	dir.OnChanged = func(s string) {
		// TODO: also check if string is a directory, and only enable if so
		if dir.Text != "" {
			gobtn.Enable()
		} else {
			gobtn.Disable()
		}
	}

	openbtn := widget.NewButtonWithIcon("Choose folder", theme.FolderOpenIcon(), func() {
		dialog.ShowFolderOpen(func(uri fyne.ListableURI, err error) {
			if err == nil && uri != nil {
				dir.SetText(uri.Path())
			}
		}, myWindow)
	})

	progressBar := widget.NewProgressBar()

	logarea := widget.NewMultiLineEntry()
	logarea.Disable()

	// TODO: have the button be pressed if enter is pressed
	gobtn = widget.NewButtonWithIcon("Process OCR", theme.UploadIcon(), func() {
		if dir.Text == "" {
			return
		}

		gobtn.Disable()
		gobtn.SetText("Processing...")

		progressBar.SetValue(0.5)

		stdout, err := copyStdoutToChan()
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error copying stdout to chan: %v\n", err)
			return
		}

		// update log area with output from outC in a concurrent goroutine
		go func() {
			for r := range stdout {
				logarea.SetText(logarea.Text + string(r))
				logarea.CursorRow = strings.Count(logarea.Text, "\n")
				// TODO: set text on progress bar, or a label below it, to latest line printed, rather than just using a whole multiline entry like this
				// TODO: parse the stdout and set progressBar based on that
			}
		}()

		err = startProcess(log, cmd, dir.Text, filepath.Base(dir.Text), training, systess, dir.Text, tessdir)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error executing process: %v\n", err)
			return
		}

		progressBar.SetValue(1.0)
		gobtn.SetText("Process OCR")
		gobtn.Enable()
	})
	gobtn.Disable()

	diropener := container.New(layout.NewGridLayout(2), dir, openbtn)

	content := container.NewVBox(diropener, gobtn, progressBar, logarea)

	myWindow.SetContent(content)

	myWindow.Show()
	myApp.Run()

	return nil
}