Added GTK+ indeterminate ProgressBars.
This commit is contained in:
parent
bf093d534c
commit
6ee8d96a6e
|
@ -216,3 +216,7 @@ func gtk_progress_bar_set_fraction(w *gtkWidget, percent int) {
|
||||||
p := C.gdouble(percent) / 100
|
p := C.gdouble(percent) / 100
|
||||||
C.gtk_progress_bar_set_fraction(togtkprogressbar(w), p)
|
C.gtk_progress_bar_set_fraction(togtkprogressbar(w), p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func gtk_progress_bar_pulse(w *gtkWidget) {
|
||||||
|
C.gtk_progress_bar_pulse(togtkprogressbar(w))
|
||||||
|
}
|
||||||
|
|
|
@ -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 in the range [0,100], the progressBar shows that much percent complete.
|
||||||
// If percent is -1, the ProgressBar is made indeterminate.
|
// If percent is -1, the ProgressBar is made indeterminate.
|
||||||
// Otherwise, SetProgress panics.
|
// Otherwise, SetProgress panics.
|
||||||
|
// TODO what happens if you repeatedly call SetProgress(-1)?
|
||||||
func (p *ProgressBar) SetProgress(percent int) {
|
func (p *ProgressBar) SetProgress(percent int) {
|
||||||
p.lock.Lock()
|
p.lock.Lock()
|
||||||
defer p.lock.Unlock()
|
defer p.lock.Unlock()
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
package ui
|
package ui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
// ...
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type sysData struct {
|
type sysData struct {
|
||||||
|
@ -12,6 +12,7 @@ type sysData struct {
|
||||||
|
|
||||||
widget *gtkWidget
|
widget *gtkWidget
|
||||||
container *gtkWidget // for moving
|
container *gtkWidget // for moving
|
||||||
|
pulse chan bool // for sysData.progressPulse()
|
||||||
}
|
}
|
||||||
|
|
||||||
type classData struct {
|
type classData struct {
|
||||||
|
@ -285,7 +286,56 @@ func (s *sysData) delete(index int) {
|
||||||
<-ret
|
<-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) {
|
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{})
|
ret := make(chan struct{})
|
||||||
defer close(ret)
|
defer close(ret)
|
||||||
uitask <- func() {
|
uitask <- func() {
|
||||||
|
|
|
@ -129,8 +129,9 @@ func myMain() {
|
||||||
prog := 0
|
prog := 0
|
||||||
incButton := NewButton("Inc")
|
incButton := NewButton("Inc")
|
||||||
decButton := NewButton("Dec")
|
decButton := NewButton("Dec")
|
||||||
|
indetButton := NewButton("Indeterminate")
|
||||||
invalidButton := NewButton("Run Invalid Test")
|
invalidButton := NewButton("Run Invalid Test")
|
||||||
sincdec := NewHorizontalStack(incButton, decButton, invalidButton)
|
sincdec := NewHorizontalStack(incButton, decButton, indetButton, invalidButton)
|
||||||
password := NewPasswordEdit()
|
password := NewPasswordEdit()
|
||||||
s0 := NewVerticalStack(s2, c, cb1, cb2, e, s3, pbar, sincdec, Space(), password)
|
s0 := NewVerticalStack(s2, c, cb1, cb2, e, s3, pbar, sincdec, Space(), password)
|
||||||
s0.SetStretchy(8)
|
s0.SetStretchy(8)
|
||||||
|
@ -224,6 +225,8 @@ mainloop:
|
||||||
prog = 0
|
prog = 0
|
||||||
}
|
}
|
||||||
pbar.SetProgress(prog)
|
pbar.SetProgress(prog)
|
||||||
|
case <-indetButton.Clicked:
|
||||||
|
pbar.SetProgress(-1)
|
||||||
case <-invalidButton.Clicked:
|
case <-invalidButton.Clicked:
|
||||||
invalidTest(cb1, lb1, nil, nil)
|
invalidTest(cb1, lb1, nil, nil)
|
||||||
}
|
}
|
||||||
|
|
1
todo.md
1
todo.md
|
@ -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
|
- 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:
|
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?))
|
- 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)
|
- 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
|
- also provide a method to center windows; Cocoa provides one for us but
|
||||||
|
|
Loading…
Reference in New Issue