// show displays the form box. It should only be called if no semantic errors are present
func (this *GUIForm) show(window *ui.Window) {
	log.WithFields(log.Fields{"identifier": this.Form.Identifier()}).Info("Showing form")

	this.FormContainer = ui.NewVerticalBox()
	window.SetChild(this.FormContainer)
}
Ejemplo n.º 2
0
func myMain() {
	var cmd *exec.Cmd
	var timer *time.Timer
	var timerChan <-chan time.Time
	var w *ui.Window

	status := ui.NewLabel("")

	stop := func() {
		if cmd != nil { // stop the command if it's running
			err := cmd.Process.Kill()
			if err != nil {
				ui.MsgBoxError(w,
					fmt.Sprintf("Error killing process: %v", err),
					"You may need to kill it manually.")
			}
			err = cmd.Process.Release()
			if err != nil {
				ui.MsgBoxError(w,
					fmt.Sprintf("Error releasing process: %v", err),
					"")
			}
			cmd = nil
		}
		if timer != nil { // stop the timer if we started it
			timer.Stop()
			timer = nil
			timerChan = nil
		}
		status.SetText("")
	}

	w = ui.NewWindow("wakeup", 400, 100)
	ui.AppQuit = w.Closing // treat application close as main window close
	cmdbox := ui.NewLineEdit(defCmdLine)
	timebox := ui.NewLineEdit(defTime)
	bStart := ui.NewButton("Start")
	bStop := ui.NewButton("Stop")

	// a Stack to keep both buttons at the same size
	btnbox := ui.NewHorizontalStack(bStart, bStop)
	btnbox.SetStretchy(0)
	btnbox.SetStretchy(1)
	// and a Stack around that Stack to keep them at a reasonable size, with space to their right
	btnbox = ui.NewHorizontalStack(btnbox, status)

	// the main layout
	grid := ui.NewGrid(2,
		ui.NewLabel("Command"), cmdbox,
		ui.NewLabel("Time"), timebox,
		ui.Space(), ui.Space(), // the Space on the right will consume the window blank space
		ui.Space(), btnbox)
	grid.SetStretchy(2, 1) // make the Space noted above consume
	grid.SetFilling(0, 1)  // make the two textboxes grow horizontally
	grid.SetFilling(1, 1)

	w.Open(grid)

mainloop:
	for {
		select {
		case <-w.Closing:
			break mainloop
		case <-bStart.Clicked:
			stop() // only one alarm at a time
			alarmTime, err := time.Parse(timeFmt, timebox.Text())
			if err != nil {
				ui.MsgBoxError(w,
					fmt.Sprintf("Error parsing time %q: %v", timebox.Text(), err),
					fmt.Sprintf("Make sure your time is in the form %q (without quotes).", timeFmt))
				continue
			}
			now := time.Now()
			later := bestTime(now, alarmTime)
			timer = time.NewTimer(later.Sub(now))
			timerChan = timer.C
			status.SetText("Started")
		case <-timerChan:
			cmd = exec.Command("/bin/sh", "-c", "exec "+cmdbox.Text())
			// keep stdin /dev/null in case user wants to run multiple alarms on one instance (TODO should I allow this program to act as a pipe?)
			// keep stdout /dev/null to avoid stty mucking
			cmd.Stderr = os.Stderr
			err := cmd.Start()
			status.SetText("Firing")
			if err != nil {
				ui.MsgBoxError(w,
					fmt.Sprintf("Error running program: %v", err),
					"")
				cmd = nil
				status.SetText("")
			}
			timer = nil
			timerChan = nil
		case <-bStop.Clicked:
			stop()
		}
	}

	// clean up
	stop()
}