diff options
Diffstat (limited to 'vendor/github.com/aarzilli/nucular/gio.go')
-rw-r--r-- | vendor/github.com/aarzilli/nucular/gio.go | 253 |
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)} +} |