aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/aarzilli/nucular/gio.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/aarzilli/nucular/gio.go')
-rw-r--r--vendor/github.com/aarzilli/nucular/gio.go253
1 files changed, 142 insertions, 111 deletions
diff --git a/vendor/github.com/aarzilli/nucular/gio.go b/vendor/github.com/aarzilli/nucular/gio.go
index 1b6adf3..d8adeaf 100644
--- a/vendor/github.com/aarzilli/nucular/gio.go
+++ b/vendor/github.com/aarzilli/nucular/gio.go
@@ -13,6 +13,7 @@ import (
"sync"
"sync/atomic"
"time"
+ "unicode/utf8"
"unsafe"
"gioui.org/app"
@@ -46,6 +47,7 @@ type masterWindow struct {
Title string
initialSize image.Point
size image.Point
+ onClose func()
w *app.Window
ops op.Ops
@@ -81,6 +83,11 @@ func (mw *masterWindow) Main() {
go func() {
mw.w = app.NewWindow(app.Title(mw.Title), app.Size(unit.Px(float32(mw.ctx.scale(mw.initialSize.X))), unit.Px(float32(mw.ctx.scale(mw.initialSize.Y)))))
mw.main()
+ if mw.onClose != nil {
+ mw.onClose()
+ } else {
+ os.Exit(0)
+ }
}()
go mw.updater()
app.Main()
@@ -95,7 +102,7 @@ func (mw *masterWindow) Unlock() {
}
func (mw *masterWindow) Close() {
- os.Exit(0) // Bad...
+ mw.w.Close()
}
func (mw *masterWindow) Closed() bool {
@@ -104,9 +111,13 @@ func (mw *masterWindow) Closed() bool {
return mw.closed
}
+func (mw *masterWindow) OnClose(onClose func()) {
+ mw.onClose = onClose
+}
+
func (mw *masterWindow) main() {
- for {
- e := <-mw.w.Events()
+ perfString := ""
+ for e := range mw.w.Events() {
switch e := e.(type) {
case system.DestroyEvent:
mw.uilock.Lock()
@@ -121,15 +132,49 @@ func (mw *masterWindow) main() {
mw.size = e.Size
mw.uilock.Lock()
mw.prevCmds = mw.prevCmds[:0]
- mw.updateLocked()
+ mw.updateLocked(perfString)
mw.uilock.Unlock()
e.Frame(&mw.ops)
+
+ case profile.Event:
+ perfString = e.Timings
+ case pointer.Event:
+ mw.uilock.Lock()
+ mw.processPointerEvent(e)
+ mw.uilock.Unlock()
+ case key.EditEvent:
+ changed := atomic.LoadInt32(&mw.ctx.changed)
+ if changed < 2 {
+ atomic.StoreInt32(&mw.ctx.changed, 2)
+ }
+ mw.uilock.Lock()
+ io.WriteString(&mw.textbuffer, e.Text)
+ mw.uilock.Unlock()
+
+ case key.Event:
+ changed := atomic.LoadInt32(&mw.ctx.changed)
+ if changed < 2 {
+ atomic.StoreInt32(&mw.ctx.changed, 2)
+ }
+ if e.State == key.Press {
+ mw.uilock.Lock()
+ switch e.Name {
+ case key.NameEnter, key.NameReturn:
+ io.WriteString(&mw.textbuffer, "\n")
+ }
+ mw.ctx.Input.Keyboard.Keys = append(mw.ctx.Input.Keyboard.Keys, gio2mobileKey(e))
+ mw.uilock.Unlock()
+ }
}
}
}
func (mw *masterWindow) processPointerEvent(e pointer.Event) {
+ changed := atomic.LoadInt32(&mw.ctx.changed)
+ if changed < 2 {
+ atomic.StoreInt32(&mw.ctx.changed, 2)
+ }
switch e.Type {
case pointer.Release, pointer.Cancel:
for i := range mw.ctx.Input.Mouse.Buttons {
@@ -144,11 +189,11 @@ func (mw *masterWindow) processPointerEvent(e pointer.Event) {
var button mouse.Button
switch {
- case e.Buttons.Contain(pointer.ButtonLeft):
+ case e.Buttons.Contain(pointer.ButtonPrimary):
button = mouse.ButtonLeft
- case e.Buttons.Contain(pointer.ButtonRight):
+ case e.Buttons.Contain(pointer.ButtonSecondary):
button = mouse.ButtonRight
- case e.Buttons.Contain(pointer.ButtonMiddle):
+ case e.Buttons.Contain(pointer.ButtonTertiary):
button = mouse.ButtonMiddle
}
@@ -169,7 +214,7 @@ func (mw *masterWindow) processPointerEvent(e pointer.Event) {
btn.Clicked = true
btn.Down = down
- case pointer.Move:
+ case pointer.Move, pointer.Drag, pointer.Scroll:
mw.ctx.Input.Mouse.Pos.X = int(e.Position.X)
mw.ctx.Input.Mouse.Pos.Y = int(e.Position.Y)
mw.ctx.Input.Mouse.Delta = mw.ctx.Input.Mouse.Pos.Sub(mw.ctx.Input.Mouse.Prev)
@@ -219,6 +264,19 @@ func init() {
runeToCode[key.NamePageUp] = mkey.CodePageUp
runeToCode[key.NamePageDown] = mkey.CodePageDown
runeToCode[key.NameTab] = mkey.CodeTab
+
+ runeToCode["F1"] = mkey.CodeF1
+ runeToCode["F2"] = mkey.CodeF2
+ runeToCode["F3"] = mkey.CodeF3
+ runeToCode["F4"] = mkey.CodeF4
+ runeToCode["F5"] = mkey.CodeF5
+ runeToCode["F6"] = mkey.CodeF6
+ runeToCode["F7"] = mkey.CodeF7
+ runeToCode["F8"] = mkey.CodeF8
+ runeToCode["F9"] = mkey.CodeF9
+ runeToCode["F10"] = mkey.CodeF10
+ runeToCode["F11"] = mkey.CodeF11
+ runeToCode["F12"] = mkey.CodeF12
}
func gio2mobileKey(e key.Event) mkey.Event {
@@ -275,27 +333,7 @@ func (w *masterWindow) updater() {
}
}
-func (mw *masterWindow) updateLocked() {
- perfString := ""
- q := mw.w.Queue()
- for _, e := range q.Events(mw.ctx) {
- switch e := e.(type) {
- case profile.Event:
- perfString = e.Timings
- case pointer.Event:
- mw.processPointerEvent(e)
- case key.EditEvent:
- io.WriteString(&mw.textbuffer, e.Text)
-
- case key.Event:
- switch e.Name {
- case key.NameEnter, key.NameReturn:
- io.WriteString(&mw.textbuffer, "\n")
- }
- mw.ctx.Input.Keyboard.Keys = append(mw.ctx.Input.Keyboard.Keys, gio2mobileKey(e))
- }
- }
-
+func (mw *masterWindow) updateLocked(perfString string) {
mw.ctx.Windows[0].Bounds = rect.Rect{X: 0, Y: 0, W: mw.size.X, H: mw.size.Y}
in := &mw.ctx.Input
in.Mouse.clip = nk_null_rect
@@ -341,11 +379,9 @@ func (mw *masterWindow) updateLocked() {
paintRect := f32.Rectangle{f32.Point{float32(pos.X), float32(pos.Y)}, f32.Point{float32(pos.X + bounds.X), float32(pos.Y + bounds.Y)}}
- var stack op.StackOp
- stack.Push(&mw.ops)
- paint.ColorOp{Color: color.RGBA{0xff, 0xff, 0xff, 0xff}}.Add(&mw.ops)
- paint.PaintOp{Rect: paintRect}.Add(&mw.ops)
- stack.Pop()
+ stack := op.Save(&mw.ops)
+ paint.FillShape(&mw.ops, color.NRGBA{0xff, 0xff, 0xff, 0xff}, gioclip.UniformRRect(paintRect, 0).Op(&mw.ops))
+ stack.Load()
drawText(&mw.ops, txt, font, color.RGBA{0x00, 0x00, 0x00, 0xff}, pos, bounds, paintRect)
}
@@ -367,10 +403,10 @@ func (ctx *context) Draw(ops *op.Ops, size image.Point, perf bool) int {
if perf {
profile.Op{ctx}.Add(ops)
}
- pointer.InputOp{ctx, false}.Add(ops)
- key.InputOp{ctx, true}.Add(ops)
+ pointer.InputOp{ctx, false, pointer.Cancel | pointer.Press | pointer.Release | pointer.Move | pointer.Drag | pointer.Scroll, image.Rect(0, 0, 4096, 4096)}.Add(ops)
+ key.InputOp{ctx}.Add(ops)
- var scissorStack op.StackOp
+ var scissorStack op.StateOp
scissorless := true
for i := range ctx.cmds {
@@ -378,18 +414,17 @@ func (ctx *context) Draw(ops *op.Ops, size image.Point, perf bool) int {
switch icmd.Kind {
case command.ScissorCmd:
if !scissorless {
- scissorStack.Pop()
+ scissorStack.Load()
}
- scissorStack.Push(ops)
- gioclip.Rect{Rect: n2fRect(icmd.Rect)}.Op(ops).Add(ops)
+ scissorStack = op.Save(ops)
+ gioclip.Rect(icmd.Rect.Rectangle()).Add(ops)
scissorless = false
case command.LineCmd:
cmd := icmd.Line
- var stack op.StackOp
- stack.Push(ops)
- paint.ColorOp{Color: cmd.Color}.Add(ops)
+ stack := op.Save(ops)
+ paint.ColorOp{Color: toNRGBA(cmd.Color)}.Add(ops)
h1 := int(cmd.LineThickness / 2)
h2 := int(cmd.LineThickness) - h1
@@ -399,17 +434,15 @@ func (ctx *context) Draw(ops *op.Ops, size image.Point, perf bool) int {
if y0 > y1 {
y0, y1 = y1, y0
}
- paint.PaintOp{Rect: f32.Rectangle{
- f32.Point{float32(cmd.Begin.X - h1), float32(y0)},
- f32.Point{float32(cmd.Begin.X + h2), float32(y1)}}}.Add(ops)
+ gioclip.Rect{image.Point{cmd.Begin.X - h1, y0}, image.Point{cmd.Begin.X + h2, y1}}.Add(ops)
+ paint.PaintOp{}.Add(ops)
} else if cmd.Begin.Y == cmd.End.Y {
x0, x1 := cmd.Begin.X, cmd.End.X
if x0 > x1 {
x0, x1 = x1, x0
}
- paint.PaintOp{Rect: f32.Rectangle{
- f32.Point{float32(x0), float32(cmd.Begin.Y - h1)},
- f32.Point{float32(x1), float32(cmd.Begin.Y + h2)}}}.Add(ops)
+ gioclip.Rect{image.Point{x0, cmd.Begin.Y - h1}, image.Point{x1, cmd.Begin.Y + h2}}.Add(ops)
+ paint.PaintOp{}.Add(ops)
} else {
m := float32(cmd.Begin.Y-cmd.End.Y) / float32(cmd.Begin.X-cmd.End.X)
invm := -1 / m
@@ -429,33 +462,26 @@ func (ctx *context) Draw(ops *op.Ops, size image.Point, perf bool) int {
pd := f32.Point{-2 * xadv, -2 * yadv}
p.Line(pd)
p.Line(f32.Point{float32(cmd.Begin.X - cmd.End.X), float32(cmd.Begin.Y - cmd.End.Y)})
+ p.Close()
- p.End().Add(ops)
+ gioclip.Outline{Path: p.End()}.Op().Add(ops)
pb = pb.Add(pa)
pc = pc.Add(pb)
pd = pd.Add(pc)
- minp := f32.Point{
- min4(pa.X, pb.X, pc.X, pd.X),
- min4(pa.Y, pb.Y, pc.Y, pd.Y)}
- maxp := f32.Point{
- max4(pa.X, pb.X, pc.X, pd.X),
- max4(pa.Y, pb.Y, pc.Y, pd.Y)}
-
- paint.PaintOp{Rect: f32.Rectangle{minp, maxp}}.Add(ops)
+ paint.PaintOp{}.Add(ops)
}
- stack.Pop()
+ stack.Load()
case command.RectFilledCmd:
cmd := icmd.RectFilled
// rounding is true if rounding has been requested AND we can draw it
rounding := cmd.Rounding > 0 && int(cmd.Rounding*2) < icmd.W && int(cmd.Rounding*2) < icmd.H
- var stack op.StackOp
- stack.Push(ops)
- paint.ColorOp{Color: cmd.Color}.Add(ops)
+ stack := op.Save(ops)
+ paint.ColorOp{Color: toNRGBA(cmd.Color)}.Add(ops)
if rounding {
const c = 0.55228475 // 4*(sqrt(2)-1)/3
@@ -473,19 +499,20 @@ func (ctx *context) Draw(ops *op.Ops, size image.Point, perf bool) int {
b.Cube(f32.Point{X: 0, Y: -r * c}, f32.Point{X: r - r*c, Y: -r}, f32.Point{X: r, Y: -r}) // NW
b.Line(f32.Point{X: w - r - r, Y: 0})
b.Cube(f32.Point{X: r * c, Y: 0}, f32.Point{X: r, Y: r - r*c}, f32.Point{X: r, Y: r}) // NE
- b.End().Add(ops)
+ b.Close()
+ gioclip.Outline{Path: b.End()}.Op().Add(ops)
}
- paint.PaintOp{Rect: n2fRect(icmd.Rect)}.Add(ops)
- stack.Pop()
+ gioclip.Rect(icmd.Rect.Rectangle()).Add(ops)
+ paint.PaintOp{}.Add(ops)
+ stack.Load()
case command.TriangleFilledCmd:
cmd := icmd.TriangleFilled
- var stack op.StackOp
- stack.Push(ops)
+ stack := op.Save(ops)
- paint.ColorOp{cmd.Color}.Add(ops)
+ paint.ColorOp{toNRGBA(cmd.Color)}.Add(ops)
var p gioclip.Path
p.Begin(ops)
@@ -493,25 +520,17 @@ func (ctx *context) Draw(ops *op.Ops, size image.Point, perf bool) int {
p.Line(f32.Point{float32(cmd.B.X - cmd.A.X), float32(cmd.B.Y - cmd.A.Y)})
p.Line(f32.Point{float32(cmd.C.X - cmd.B.X), float32(cmd.C.Y - cmd.B.Y)})
p.Line(f32.Point{float32(cmd.A.X - cmd.C.X), float32(cmd.A.Y - cmd.C.Y)})
- p.End().Add(ops)
-
- pmin := f32.Point{
- min2(min2(float32(cmd.A.X), float32(cmd.B.X)), float32(cmd.C.X)),
- min2(min2(float32(cmd.A.Y), float32(cmd.B.Y)), float32(cmd.C.Y))}
+ p.Close()
+ gioclip.Outline{Path: p.End()}.Op().Add(ops)
- pmax := f32.Point{
- max2(max2(float32(cmd.A.X), float32(cmd.B.X)), float32(cmd.C.X)),
- max2(max2(float32(cmd.A.Y), float32(cmd.B.Y)), float32(cmd.C.Y))}
+ paint.PaintOp{}.Add(ops)
- paint.PaintOp{Rect: f32.Rectangle{pmin, pmax}}.Add(ops)
-
- stack.Pop()
+ stack.Load()
case command.CircleFilledCmd:
- var stack op.StackOp
- stack.Push(ops)
+ stack := op.Save(ops)
- paint.ColorOp{icmd.CircleFilled.Color}.Add(ops)
+ paint.ColorOp{toNRGBA(icmd.CircleFilled.Color)}.Add(ops)
r := min2(float32(icmd.W), float32(icmd.H)) / 2
@@ -523,19 +542,20 @@ func (ctx *context) Draw(ops *op.Ops, size image.Point, perf bool) int {
b.Cube(f32.Point{X: -r * c, Y: 0}, f32.Point{X: -r, Y: -r + r*c}, f32.Point{X: -r, Y: -r}) // SW
b.Cube(f32.Point{X: 0, Y: -r * c}, f32.Point{X: r - r*c, Y: -r}, f32.Point{X: r, Y: -r}) // NW
b.Cube(f32.Point{X: r * c, Y: 0}, f32.Point{X: r, Y: r - r*c}, f32.Point{X: r, Y: r}) // NE
- b.End().Add(ops)
+ gioclip.Outline{Path: b.End()}.Op().Add(ops)
- paint.PaintOp{Rect: n2fRect(icmd.Rect)}.Add(ops)
+ paint.PaintOp{}.Add(ops)
- stack.Pop()
+ stack.Load()
case command.ImageCmd:
- var stack op.StackOp
- stack.Push(ops)
+ stack := op.Save(ops)
//TODO: this should be retained between frames somehow...
paint.NewImageOp(icmd.Image.Img).Add(ops)
- paint.PaintOp{n2fRect(icmd.Rect)}.Add(ops)
- stack.Pop()
+ op.Offset(f32.Point{float32(icmd.Rect.X), float32(icmd.Rect.Y)}).Add(ops)
+ gioclip.Rect{image.Point{0, 0}, image.Point{icmd.Rect.W, icmd.Rect.H}}.Add(ops)
+ paint.PaintOp{}.Add(ops)
+ stack.Load()
case command.TextCmd:
txt := fontFace2fontFace(&icmd.Text.Face).layout(icmd.Text.String, -1)
@@ -618,21 +638,26 @@ func textPadding(lines []text.Line) (padding image.Rectangle) {
func clipLine(line text.Line, clip image.Rectangle) (text.Line, f32.Point, bool) {
off := fixed.Point26_6{X: fixed.I(0), Y: fixed.I(line.Ascent.Ceil())}
- for len(line.Layout) > 0 {
- adv := line.Layout[0].Advance
+ for len(line.Layout.Advances) > 0 {
+ adv := line.Layout.Advances[0]
+ _, n := utf8.DecodeRuneInString(line.Layout.Text)
if (off.X + adv + line.Bounds.Max.X - line.Width).Ceil() >= clip.Min.X {
break
}
off.X += adv
- line.Layout = line.Layout[1:]
+ line.Layout.Text = line.Layout.Text[n:]
+ line.Layout.Advances = line.Layout.Advances[1:]
}
endx := off.X
- for i, glyph := range line.Layout {
+ rune := 0
+ for n, _ := range line.Layout.Text {
if (endx + line.Bounds.Min.X).Floor() > clip.Max.X {
- line.Layout = line.Layout[:i]
+ line.Layout.Advances = line.Layout.Advances[:rune]
+ line.Layout.Text = line.Layout.Text[:n]
break
}
- endx += glyph.Advance
+ endx += line.Layout.Advances[rune]
+ rune++
}
offf := f32.Point{X: float32(off.X) / 64, Y: float32(off.Y) / 64}
return line, offf, true
@@ -652,9 +677,8 @@ func drawText(ops *op.Ops, txt []text.Line, face font.Face, fgcolor color.RGBA,
clip := textPadding(txt)
clip.Max = clip.Max.Add(bounds)
- var stack op.StackOp
- stack.Push(ops)
- paint.ColorOp{fgcolor}.Add(ops)
+ stack := op.Save(ops)
+ paint.ColorOp{toNRGBA(fgcolor)}.Add(ops)
fc := fontFace2fontFace(&face)
@@ -667,23 +691,23 @@ func drawText(ops *op.Ops, txt []text.Line, face font.Face, fgcolor color.RGBA,
off.X += float32(pos.X)
off.Y += float32(pos.Y) + float32(i*FontHeight(face))
- var stack op.StackOp
- stack.Push(ops)
+ stack := op.Save(ops)
- op.TransformOp{}.Offset(off).Add(ops)
+ op.Offset(off).Add(ops)
fc.shape(txtstr.Layout).Add(ops)
- paint.PaintOp{Rect: paintRect.Sub(off)}.Add(ops)
+ gioclip.UniformRRect(paintRect.Sub(off), 0).Add(ops)
+ paint.PaintOp{}.Add(ops)
- stack.Pop()
+ stack.Load()
}
- stack.Pop()
+ stack.Load()
}
type fontFace struct {
fnt *opentype.Font
- shaper *text.FontRegistry
+ shaper *text.Cache
size int
fsize fixed.Int26_6
metrics ifont.Metrics
@@ -700,7 +724,7 @@ func (face *fontFace) layout(str string, width int) []text.Line {
return face.shaper.LayoutString(text.Font{}, fixed.I(face.size), width, str)
}
-func (face *fontFace) shape(txtstr []text.Glyph) op.CallOp {
+func (face *fontFace) shape(txtstr text.Layout) op.CallOp {
return face.shaper.Shape(text.Font{}, fixed.I(face.size), txtstr)
}
@@ -817,11 +841,18 @@ func widgetTextWrap(o *command.Buffer, b rect.Rect, str []rune, t *textWidget, f
if line.Y+line.H >= (b.Y + b.H) {
break
}
- runes := make([]rune, len(txtline.Layout))
- for i := range txtline.Layout {
- runes[i] = txtline.Layout[i].Rune
- }
- widgetText(o, line, string(runes), &text, "LC", f)
+ widgetText(o, line, txtline.Layout.Text, &text, "LC", f)
line.Y += FontHeight(f) + 2*t.Padding.Y
}
}
+
+func toNRGBA(c color.RGBA) color.NRGBA {
+ if c.A == 0xff {
+ return color.NRGBA{c.R, c.G, c.B, c.A}
+ }
+ r, g, b, a := c.RGBA()
+ r = (r * 0xffff) / a
+ g = (g * 0xffff) / a
+ b = (b * 0xffff) / a
+ return color.NRGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
+}