126 lines
2.6 KiB
Go
126 lines
2.6 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"math/rand"
|
|
"os"
|
|
"sort"
|
|
"strings"
|
|
|
|
qt "github.com/mappu/miqt/qt6"
|
|
"github.com/mappu/miqt/qt6/mainthread"
|
|
)
|
|
|
|
func main() {
|
|
|
|
qt.NewQApplication(os.Args)
|
|
appName := "SortVote"
|
|
qt.QCoreApplication_SetApplicationName(appName)
|
|
|
|
if len(os.Args) < 2 {
|
|
qt.QMessageBox_Critical(nil, appName, "Usage: ./sortvote filename.txt")
|
|
os.Exit(1)
|
|
}
|
|
|
|
b, err := os.ReadFile(os.Args[1])
|
|
if err != nil {
|
|
qt.QMessageBox_Critical(nil, appName, fmt.Sprintf("Error reading file %q: %s", os.Args[1], err.Error()))
|
|
os.Exit(1)
|
|
}
|
|
|
|
file_lines := strings.Split(string(b), "\n")
|
|
entries := make([]string, 0, len(file_lines))
|
|
for _, line := range file_lines {
|
|
if len(line) > 0 && line[0] != '#' {
|
|
entries = append(entries, line)
|
|
}
|
|
}
|
|
|
|
// Start with a randomized order for fairness
|
|
|
|
for i := range entries {
|
|
j := rand.Intn(i + 1)
|
|
entries[i], entries[j] = entries[j], entries[i]
|
|
}
|
|
|
|
//
|
|
|
|
ui := NewMainWindowUi()
|
|
ui.MainWindow.SetWindowTitle(os.Args[1] + " - " + appName)
|
|
|
|
ui.infoArea.AddItem(fmt.Sprintf("Sorting %d entries", len(entries)))
|
|
ui.infoArea.AddItem("Use [Q] and [Z] to select with the keyboard")
|
|
ui.infoArea.ScrollToBottom()
|
|
|
|
active := true
|
|
ret := make(chan bool, 0)
|
|
ui.b1.OnClicked(func() { // Set up click handlers only once
|
|
ret <- true
|
|
})
|
|
ui.b2.OnClicked(func() {
|
|
ret <- false
|
|
})
|
|
|
|
ui.MainWindow.OnKeyPressEvent(func(super func(event *qt.QKeyEvent), event *qt.QKeyEvent) {
|
|
if !active {
|
|
super(event)
|
|
return
|
|
}
|
|
|
|
keytext := strings.ToLower(event.Text())
|
|
if keytext == `q` {
|
|
ret <- true
|
|
|
|
} else if keytext == `z` {
|
|
ret <- false
|
|
|
|
} else { // not our event
|
|
super(event)
|
|
}
|
|
|
|
})
|
|
|
|
ui.MainWindow.Show()
|
|
|
|
ui.infoArea.SetFocusPolicy(qt.NoFocus) // prevent stealing keyboard input
|
|
|
|
comparisons := 0
|
|
|
|
go func() {
|
|
sort.SliceStable(entries, func(i, j int) bool {
|
|
|
|
mainthread.Wait(func() {
|
|
comparisons++
|
|
|
|
ui.infoArea.AddItem(fmt.Sprintf("Comparison #%d", comparisons))
|
|
ui.infoArea.ScrollToBottom()
|
|
|
|
// Escape & used as an alt-accelerator
|
|
ui.b1.SetText(strings.ReplaceAll(entries[i], `&`, `&&`))
|
|
ui.b2.SetText(strings.ReplaceAll(entries[j], `&`, `&&`))
|
|
})
|
|
|
|
return <-ret
|
|
})
|
|
active = false
|
|
|
|
mainthread.Start(func() {
|
|
ui.b1.SetEnabled(false)
|
|
ui.b2.SetEnabled(false)
|
|
|
|
// Sorting 39 entries took 77 comparisons
|
|
// Finished sorting 37 entries in 219 comparisons
|
|
// 37 x log_2(37) = 192 so we are 15% over(?)
|
|
|
|
ui.infoArea.AddItem(fmt.Sprintf("Finished sorting %d entries in %d comparisons", len(entries), comparisons))
|
|
|
|
for i, ent := range entries {
|
|
ui.infoArea.AddItem(fmt.Sprintf("%02d. %s", i+1, ent))
|
|
ui.infoArea.ScrollToBottom()
|
|
}
|
|
})
|
|
}()
|
|
|
|
qt.QApplication_Exec()
|
|
}
|