package main import ( "fmt" "math/rand" "os" "sort" "strings" qt "github.com/mappu/miqt/qt6" "github.com/mappu/miqt/qt6/mainthread" ) func formatButtonText(s string) string { // Escape & used as an alt-accelerator s = strings.ReplaceAll(s, `&`, `&&`) // Replace " - " with newlines s = strings.ReplaceAll(s, ` - `, "\n") return s } 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 { // Towards the end, sort.SliceStable has the pattern of putting one // entry in the top button all the time // Maybe shuffle them shuf := (rand.Int()%2 == 0) if shuf { i, j = j, i } mainthread.Wait(func() { comparisons++ ui.infoArea.AddItem(fmt.Sprintf("Comparison #%d", comparisons)) ui.infoArea.ScrollToBottom() ui.b1.SetText(formatButtonText(entries[i])) ui.b2.SetText(formatButtonText(entries[j])) }) if shuf { return !<-ret } return <-ret }) active = false mainthread.Start(func() { ui.b1.SetVisible(false) ui.b2.SetVisible(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() }