aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfaiface <faiface2202@gmail.com>2019-05-02 01:01:02 +0200
committerfaiface <faiface2202@gmail.com>2019-05-02 01:01:02 +0200
commit7bbe7dc9618949f2fe023efcb896a70150966e44 (patch)
tree26c04eafd111309558272bc453106c63307b61ee
parentd07cc4a0af7f602fe3d519faca01b3abfce2e9b2 (diff)
downloadgui-7bbe7dc9618949f2fe023efcb896a70150966e44.zip
revamp the whole thing for a fresh new start
-rw-r--r--env.go11
-rw-r--r--event.go49
-rw-r--r--layout/interface.go23
-rw-r--r--mux.go86
-rw-r--r--win/win.go78
5 files changed, 200 insertions, 47 deletions
diff --git a/env.go b/env.go
new file mode 100644
index 0000000..cd71b5b
--- /dev/null
+++ b/env.go
@@ -0,0 +1,11 @@
+package gui
+
+import (
+ "image"
+ "image/draw"
+)
+
+type Env struct {
+ Events <-chan Event
+ Draw chan<- func(draw.Image) image.Rectangle
+}
diff --git a/event.go b/event.go
new file mode 100644
index 0000000..3440926
--- /dev/null
+++ b/event.go
@@ -0,0 +1,49 @@
+package gui
+
+import "fmt"
+
+type Event string
+
+func Eventf(format string, a ...interface{}) Event {
+ return Event(fmt.Sprintf(format, a...))
+}
+
+func (e Event) Matches(format string, a ...interface{}) bool {
+ _, err := fmt.Sscanf(string(e), format, a...)
+ return err == nil
+}
+
+func MakeEventsChan() (<-chan Event, chan<- Event) {
+ out, in := make(chan Event), make(chan Event)
+
+ go func() {
+ var queue []Event
+
+ for {
+ x, ok := <-in
+ if !ok {
+ close(out)
+ return
+ }
+ queue = append(queue, x)
+
+ for len(queue) > 0 {
+ select {
+ case out <- queue[0]:
+ queue = queue[1:]
+ case x, ok := <-in:
+ if !ok {
+ for _, x := range queue {
+ out <- x
+ }
+ close(out)
+ return
+ }
+ queue = append(queue, x)
+ }
+ }
+ }
+ }()
+
+ return out, in
+}
diff --git a/layout/interface.go b/layout/interface.go
deleted file mode 100644
index 28b6a01..0000000
--- a/layout/interface.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package layout
-
-import (
- "fmt"
- "image"
- "image/draw"
-)
-
-type EventDrawer interface {
- Event() <-chan Event
- Draw() chan<- func(draw.Image) image.Rectangle
-}
-
-type Event string
-
-func Eventf(format string, a ...interface{}) Event {
- return Event(fmt.Sprintf(format, a...))
-}
-
-func (e Event) Matches(format string, a ...interface{}) bool {
- _, err := fmt.Sscanf(string(e), format, a...)
- return err == nil
-}
diff --git a/mux.go b/mux.go
new file mode 100644
index 0000000..cbe3488
--- /dev/null
+++ b/mux.go
@@ -0,0 +1,86 @@
+package gui
+
+import (
+ "image"
+ "image/draw"
+ "sync"
+)
+
+type Mux struct {
+ mu sync.Mutex
+ eventsIns []chan<- Event
+ draw chan<- func(draw.Image) image.Rectangle
+}
+
+func NewMux(env Env) (mux *Mux, master Env) {
+ drawChan := make(chan func(draw.Image) image.Rectangle)
+ mux = &Mux{draw: drawChan}
+ master = mux.makeEnv(true)
+
+ go func() {
+ for d := range drawChan {
+ env.Draw <- d
+ }
+ close(env.Draw)
+ }()
+
+ go func() {
+ for e := range env.Events {
+ mux.mu.Lock()
+ for _, eventsIn := range mux.eventsIns {
+ eventsIn <- e
+ }
+ mux.mu.Unlock()
+ }
+ mux.mu.Lock()
+ for _, eventsIn := range mux.eventsIns {
+ close(eventsIn)
+ }
+ mux.mu.Unlock()
+ }()
+
+ return mux, master
+}
+
+func (mux *Mux) MakeEnv() Env {
+ return mux.makeEnv(false)
+}
+
+func (mux *Mux) makeEnv(master bool) Env {
+ eventsOut, eventsIn := MakeEventsChan()
+ drawChan := make(chan func(draw.Image) image.Rectangle)
+ env := Env{eventsOut, drawChan}
+
+ mux.mu.Lock()
+ mux.eventsIns = append(mux.eventsIns, eventsIn)
+ mux.mu.Unlock()
+
+ go func() {
+ for d := range drawChan {
+ mux.draw <- d
+ }
+ if master {
+ mux.mu.Lock()
+ for _, eventsIn := range mux.eventsIns {
+ close(eventsIn)
+ }
+ mux.eventsIns = nil
+ close(mux.draw)
+ mux.mu.Unlock()
+ } else {
+ mux.mu.Lock()
+ i := -1
+ for i = range mux.eventsIns {
+ if mux.eventsIns[i] == eventsIn {
+ break
+ }
+ }
+ if i != -1 {
+ mux.eventsIns = append(mux.eventsIns[:i], mux.eventsIns[i+1:]...)
+ }
+ mux.mu.Unlock()
+ }
+ }()
+
+ return env
+}
diff --git a/win/win.go b/win/win.go
index 10ce5b0..552f58d 100644
--- a/win/win.go
+++ b/win/win.go
@@ -4,8 +4,10 @@ import (
"image"
"image/draw"
"runtime"
+ "time"
+ "unsafe"
- "github.com/faiface/gui/layout"
+ "github.com/faiface/gui"
"github.com/faiface/mainthread"
"github.com/go-gl/gl/v2.1/gl"
"github.com/go-gl/glfw/v3.2/glfw"
@@ -49,11 +51,14 @@ func New(opts ...Option) (*Win, error) {
opt(&o)
}
+ eventsOut, eventsIn := gui.MakeEventsChan()
+
w := &Win{
- event: make(chan layout.Event),
- draw: make(chan func(draw.Image) image.Rectangle),
- newSize: make(chan image.Rectangle),
- finish: make(chan struct{}),
+ eventsOut: eventsOut,
+ eventsIn: eventsIn,
+ draw: make(chan func(draw.Image) image.Rectangle),
+ newSize: make(chan image.Rectangle),
+ finish: make(chan struct{}),
}
var err error
@@ -96,8 +101,9 @@ func makeGLFWWin(o *options) (*glfw.Window, error) {
}
type Win struct {
- event chan layout.Event
- draw chan func(draw.Image) image.Rectangle
+ eventsOut <-chan gui.Event
+ eventsIn chan<- gui.Event
+ draw chan func(draw.Image) image.Rectangle
newSize chan image.Rectangle
finish chan struct{}
@@ -106,12 +112,8 @@ type Win struct {
img *image.RGBA
}
-func (w *Win) Event() <-chan layout.Event {
- return w.event
-}
-
-func (w *Win) Draw() chan<- func(draw.Image) image.Rectangle {
- return w.draw
+func (w *Win) Env() gui.Env {
+ return gui.Env{Events: w.eventsOut, Draw: w.draw}
}
func (w *Win) eventThread() {
@@ -120,38 +122,38 @@ func (w *Win) eventThread() {
w.w.SetMouseButtonCallback(func(_ *glfw.Window, button glfw.MouseButton, action glfw.Action, mod glfw.ModifierKey) {
switch action {
case glfw.Press:
- w.event <- layout.Eventf("mo/down/%d/%d", moX, moY)
+ w.eventsIn <- gui.Eventf("mo/down/%d/%d", moX, moY)
case glfw.Release:
- w.event <- layout.Eventf("mo/up/%d/%d", moX, moY)
+ w.eventsIn <- gui.Eventf("mo/up/%d/%d", moX, moY)
}
})
w.w.SetCursorPosCallback(func(_ *glfw.Window, x, y float64) {
moX, moY = int(x), int(y)
- w.event <- layout.Eventf("mo/move/%d/%d", moX, moY)
+ w.eventsIn <- gui.Eventf("mo/move/%d/%d", moX, moY)
})
w.w.SetCharCallback(func(_ *glfw.Window, r rune) {
- w.event <- layout.Eventf("kb/type/%d", r)
+ w.eventsIn <- gui.Eventf("kb/type/%d", r)
})
w.w.SetSizeCallback(func(_ *glfw.Window, width, height int) {
r := image.Rect(0, 0, width, height)
w.newSize <- r
- w.event <- layout.Eventf("resize/%d/%d/%d/%d", r.Min.X, r.Min.Y, r.Max.X, r.Max.Y)
+ w.eventsIn <- gui.Eventf("resize/%d/%d/%d/%d", r.Min.X, r.Min.Y, r.Max.X, r.Max.Y)
})
w.w.SetCloseCallback(func(_ *glfw.Window) {
- w.event <- layout.Eventf("wi/close")
+ w.eventsIn <- gui.Eventf("wi/close")
})
r := w.img.Bounds()
- w.event <- layout.Eventf("resize/%d/%d/%d/%d", r.Min.X, r.Min.Y, r.Max.X, r.Max.Y)
+ w.eventsIn <- gui.Eventf("resize/%d/%d/%d/%d", r.Min.X, r.Min.Y, r.Max.X, r.Max.Y)
for {
select {
case <-w.finish:
- close(w.event)
+ close(w.eventsIn)
w.w.Destroy()
return
default:
@@ -164,13 +166,18 @@ func (w *Win) openGLThread() {
w.w.MakeContextCurrent()
gl.Init()
+ w.openGLFlush(w.img.Bounds())
+
+loop:
for {
+ var totalR image.Rectangle
+
select {
case r := <-w.newSize:
img := image.NewRGBA(r)
draw.Draw(img, w.img.Bounds(), w.img, w.img.Bounds().Min, draw.Src)
w.img = img
- w.openGLFlush(r)
+ totalR = totalR.Union(r)
case d, ok := <-w.draw:
if !ok {
@@ -178,7 +185,30 @@ func (w *Win) openGLThread() {
return
}
r := d(w.img)
- w.openGLFlush(r)
+ totalR = totalR.Union(r)
+ }
+
+ for {
+ select {
+ case <-time.After(time.Second / 960):
+ w.openGLFlush(totalR)
+ totalR = image.ZR
+ continue loop
+
+ case r := <-w.newSize:
+ img := image.NewRGBA(r)
+ draw.Draw(img, w.img.Bounds(), w.img, w.img.Bounds().Min, draw.Src)
+ w.img = img
+ totalR = totalR.Union(r)
+
+ case d, ok := <-w.draw:
+ if !ok {
+ close(w.finish)
+ return
+ }
+ r := d(w.img)
+ totalR = totalR.Union(r)
+ }
}
}
}
@@ -210,7 +240,7 @@ func (w *Win) openGLFlush(r image.Rectangle) {
int32(r.Dy()),
gl.RGBA,
gl.UNSIGNED_BYTE,
- gl.Ptr(tmp.Pix),
+ unsafe.Pointer(&tmp.Pix[0]),
)
gl.Flush()
}