Added GTK+ indeterminate ProgressBars.

This commit is contained in:
Pietro Gagliardi 2014-03-12 17:31:13 -04:00
parent bf093d534c
commit 6ee8d96a6e
5 changed files with 61 additions and 2 deletions

View File

@ -216,3 +216,7 @@ func gtk_progress_bar_set_fraction(w *gtkWidget, percent int) {
p := C.gdouble(percent) / 100
C.gtk_progress_bar_set_fraction(togtkprogressbar(w), p)
}
func gtk_progress_bar_pulse(w *gtkWidget) {
C.gtk_progress_bar_pulse(togtkprogressbar(w))
}

View File

@ -27,6 +27,7 @@ func NewProgressBar() *ProgressBar {
// If percent is in the range [0,100], the progressBar shows that much percent complete.
// If percent is -1, the ProgressBar is made indeterminate.
// Otherwise, SetProgress panics.
// TODO what happens if you repeatedly call SetProgress(-1)?
func (p *ProgressBar) SetProgress(percent int) {
p.lock.Lock()
defer p.lock.Unlock()

View File

@ -4,7 +4,7 @@
package ui
import (
// ...
"time"
)
type sysData struct {
@ -12,6 +12,7 @@ type sysData struct {
widget *gtkWidget
container *gtkWidget // for moving
pulse chan bool // for sysData.progressPulse()
}
type classData struct {
@ -285,7 +286,56 @@ func (s *sysData) delete(index int) {
<-ret
}
// With GTK+, we must manually pulse the indeterminate progressbar ourselves. This goroutine does that.
func (s *sysData) progressPulse() {
pulse := func() {
ret := make(chan struct{})
defer close(ret)
uitask <- func() {
gtk_progress_bar_pulse(s.widget)
ret <- struct{}{}
}
<-ret
}
var ticker *time.Ticker
var tickchan <-chan time.Time
// the default on Windows
const pulseRate = 30 * time.Millisecond
for {
select {
case start := <-s.pulse:
if start {
ticker = time.NewTicker(pulseRate)
tickchan = ticker.C
pulse() // start the pulse animation now, not 30ms later
} else {
if ticker != nil {
ticker.Stop()
}
ticker = nil
tickchan = nil
s.pulse <- true // notify sysData.setProgress()
}
case <-tickchan:
pulse()
}
}
}
func (s *sysData) setProgress(percent int) {
if s.pulse == nil {
s.pulse = make(chan bool)
go s.progressPulse()
}
if percent == -1 {
s.pulse <- true
return
}
s.pulse <- false
<-s.pulse // wait for sysData.progressPulse() to register that
ret := make(chan struct{})
defer close(ret)
uitask <- func() {

View File

@ -129,8 +129,9 @@ func myMain() {
prog := 0
incButton := NewButton("Inc")
decButton := NewButton("Dec")
indetButton := NewButton("Indeterminate")
invalidButton := NewButton("Run Invalid Test")
sincdec := NewHorizontalStack(incButton, decButton, invalidButton)
sincdec := NewHorizontalStack(incButton, decButton, indetButton, invalidButton)
password := NewPasswordEdit()
s0 := NewVerticalStack(s2, c, cb1, cb2, e, s3, pbar, sincdec, Space(), password)
s0.SetStretchy(8)
@ -224,6 +225,8 @@ mainloop:
prog = 0
}
pbar.SetProgress(prog)
case <-indetButton.Clicked:
pbar.SetProgress(-1)
case <-invalidButton.Clicked:
invalidTest(cb1, lb1, nil, nil)
}

View File

@ -23,6 +23,7 @@ so I don't forget:
- change sysData.make() so it does not take the initial window text as an argument and instead have the respective Control/Window.make() call sysData.setText() expressly; this would allow me to remove the "no such concept of text" checks from the GTK+ and Mac OS X backends
important things:
- GTK+ ProgressBar indeterminate animation is running like mad; pretty sure it's our idle task being evil
- because the main event loop is not called if initialization fails, it is presently impossible for MsgBoxError() to work if UI initialization fails; this basically means we cannot allow initializiation to fail on Mac OS X if we want to be able to report UI init failures to the user with one (which would be desirable, maybe (would violate Windows HIG?))
- figure out where to auto-place windows in Cocoa (also window coordinates are still not flipped properly so (0,0) on screen is the bottom-left)
- also provide a method to center windows; Cocoa provides one for us but