func drawDropDown(ctx *nanovgo.Context, text string, x, y, w, h float32) { var cornerRadius float32 = 4.0 bg := nanovgo.LinearGradient(x, y, x, y+h, nanovgo.RGBA(255, 255, 255, 16), nanovgo.RGBA(0, 0, 0, 16)) ctx.BeginPath() ctx.RoundedRect(x+1, y+1, w-2, h-2, cornerRadius-1) ctx.SetFillPaint(bg) ctx.Fill() ctx.BeginPath() ctx.RoundedRect(x+0.5, y+0.5, w-1, h-1, cornerRadius-0.5) ctx.SetStrokeColor(nanovgo.RGBA(0, 0, 0, 48)) ctx.Stroke() ctx.SetFontSize(20.0) ctx.SetFontFace("sans") ctx.SetFillColor(nanovgo.RGBA(255, 255, 255, 160)) ctx.SetTextAlign(nanovgo.AlignLeft | nanovgo.AlignMiddle) ctx.Text(x+h*0.3, y+h*0.5, text) ctx.SetFontSize(h * 1.3) ctx.SetFontFace("icons") ctx.SetFillColor(nanovgo.RGBA(255, 255, 255, 64)) ctx.SetTextAlign(nanovgo.AlignCenter | nanovgo.AlignMiddle) ctx.Text(x+w-h*0.5, y+h*0.5, cpToUTF8(IconCHEVRONRIGHT)) }
func drawCaps(ctx *nanovgo.Context, x, y, width float32) { caps := []nanovgo.LineCap{nanovgo.Butt, nanovgo.Round, nanovgo.Square} var lineWidth float32 = 8.0 ctx.Save() defer ctx.Restore() ctx.BeginPath() ctx.Rect(x-lineWidth/2, y, width+lineWidth, 40) ctx.SetFillColor(nanovgo.RGBA(255, 255, 255, 32)) ctx.Fill() ctx.BeginPath() ctx.Rect(x, y, width, 40) ctx.SetFillColor(nanovgo.RGBA(255, 255, 255, 32)) ctx.Fill() ctx.SetStrokeWidth(lineWidth) for i, cap := range caps { ctx.SetLineCap(cap) ctx.SetStrokeColor(nanovgo.RGBA(0, 0, 0, 255)) ctx.BeginPath() ctx.MoveTo(x, y+float32(i)*10+5) ctx.LineTo(x+width, y+float32(i)*10+5) ctx.Stroke() } }
func (g *Graph) Draw(self Widget, ctx *nanovgo.Context) { g.WidgetImplement.Draw(self, ctx) x := float32(g.x) y := float32(g.y) w := float32(g.w) h := float32(g.h) ctx.BeginPath() ctx.Rect(x, y, w, h) ctx.SetFillColor(g.backgroundColor) ctx.Fill() if len(g.values) < 2 { return } ctx.BeginPath() ctx.MoveTo(x, y+h) dx := float32(len(g.values) - 1) for i, v := range g.values { vx := x + float32(i)*w/dx vy := y + (1.0-v)*h ctx.LineTo(vx, vy) } ctx.LineTo(x+w, y+h) ctx.SetStrokeColor(nanovgo.MONO(100, 255)) ctx.Stroke() ctx.SetFillColor(g.foregroundColor) ctx.Fill() ctx.SetFontFace(g.theme.FontNormal) ctx.SetFillColor(g.textColor) if g.caption != "" { ctx.SetFontSize(14) ctx.SetTextAlign(nanovgo.AlignLeft | nanovgo.AlignTop) ctx.Text(x+3, y+1, g.caption) } if g.header != "" { ctx.SetFontSize(18) ctx.SetTextAlign(nanovgo.AlignRight | nanovgo.AlignTop) ctx.Text(x+w-3, y+1, g.header) } if g.footer != "" { ctx.SetFontSize(15) ctx.SetTextAlign(nanovgo.AlignRight | nanovgo.AlignBottom) ctx.Text(x+w-3, y+h-1, g.footer) } ctx.BeginPath() ctx.Rect(x, y, w, h) ctx.SetStrokeColor(nanovgo.MONO(100, 255)) ctx.Stroke() }
func (sf *SpinnerFilter) Draw(self nanogui.Widget, ctx *nanovgo.Context) { if sf.isActive() { var py int fw, fh := sf.Parent().Size() if window, ok := sf.Parent().(*nanogui.Window); ok { hh := window.Theme().WindowHeaderHeight py += hh fh -= hh } sf.SetPosition(0, py) sf.SetSize(fw, fh) currentTime := nanogui.GetTime() - sf.startTime var alpha float32 var showSpinner bool if sf.state == SpinnerFadeIn { if currentTime > 1 { alpha = 0.7 showSpinner = true } else { alpha = currentTime * 0.7 } } else { if currentTime > 1 { alpha = 0.7 } else { alpha = (1.0 - currentTime) * 0.7 } } ctx.Save() ctx.BeginPath() ctx.SetFillColor(nanovgo.MONOf(0, alpha)) ctx.Rect(0, float32(py), float32(fw), float32(fh)) ctx.Fill() if showSpinner { cx := float32(fw / 2) cy := float32(py + fh/2) rotation := 2 * math.Pi * float64(currentTime*float32(sf.speed)*float32(sf.num)) / float64(sf.num) dr := float64(2 * math.Pi / float64(sf.num)) ctx.SetStrokeWidth(sf.lineWidth) for i := 0; i < sf.num; i++ { ctx.BeginPath() ctx.MoveTo(cx+float32(math.Cos(rotation))*sf.c1, cy+float32(math.Sin(rotation))*sf.c1) ctx.LineTo(cx+float32(math.Cos(rotation))*sf.c2, cy+float32(math.Sin(rotation))*sf.c2) ctx.SetStrokeColor(nanovgo.MONOf(1.0, float32(i)/float32(sf.num))) ctx.Stroke() rotation += dr } } ctx.Restore() } else { sf.SetSize(0, 0) sf.SetVisible(false) return } }
func drawEditBoxBase(ctx *nanovgo.Context, x, y, w, h float32) { // Edit bg := nanovgo.BoxGradient(x+1, y+1+1.5, w-2, h-2, 3, 4, nanovgo.RGBA(255, 255, 255, 32), nanovgo.RGBA(32, 32, 32, 32)) ctx.BeginPath() ctx.RoundedRect(x+1, y+1, w-2, h-2, 4-1) ctx.SetFillPaint(bg) ctx.Fill() ctx.BeginPath() ctx.RoundedRect(x+0.5, y+0.5, w-1, h-1, 4-0.5) ctx.SetStrokeColor(nanovgo.RGBA(0, 0, 0, 48)) ctx.Stroke() }
func drawLines(ctx *nanovgo.Context, x, y, w, h, t float32) { var pad float32 = 5.0 s := w/9.0 - pad*2 joins := []nanovgo.LineCap{nanovgo.Miter, nanovgo.Round, nanovgo.Bevel} caps := []nanovgo.LineCap{nanovgo.Butt, nanovgo.Round, nanovgo.Square} ctx.Save() defer ctx.Restore() pts := []float32{ -s*0.25 + cosF(t*0.3)*s*0.5, sinF(t*0.3) * s * 0.5, -s * 0.25, 0, s * 0.25, 0, s*0.25 + cosF(-t*0.3)*s*0.5, sinF(-t*0.3) * s * 0.5, } for i, cap := range caps { for j, join := range joins { fx := x + s*0.5 + float32(i*3+j)/9.0*w + pad fy := y - s*0.5 + pad ctx.SetLineCap(cap) ctx.SetLineJoin(join) ctx.SetStrokeWidth(s * 0.3) ctx.SetStrokeColor(nanovgo.RGBA(0, 0, 0, 160)) ctx.BeginPath() ctx.MoveTo(fx+pts[0], fy+pts[1]) ctx.LineTo(fx+pts[2], fy+pts[3]) ctx.LineTo(fx+pts[4], fy+pts[5]) ctx.LineTo(fx+pts[6], fy+pts[7]) ctx.Stroke() ctx.SetLineCap(nanovgo.Butt) ctx.SetLineJoin(nanovgo.Bevel) ctx.SetStrokeWidth(1.0) ctx.SetStrokeColor(nanovgo.RGBA(0, 192, 255, 255)) ctx.BeginPath() ctx.MoveTo(fx+pts[0], fy+pts[1]) ctx.LineTo(fx+pts[2], fy+pts[3]) ctx.LineTo(fx+pts[4], fy+pts[5]) ctx.LineTo(fx+pts[6], fy+pts[7]) ctx.Stroke() } } }
func drawWidths(ctx *nanovgo.Context, x, y, width float32) { ctx.Save() defer ctx.Restore() ctx.SetStrokeColor(nanovgo.RGBA(0, 0, 0, 255)) for i := 0; i < 20; i++ { w := (float32(i) + 0.5) * 0.1 ctx.SetStrokeWidth(w) ctx.BeginPath() ctx.MoveTo(x, y) ctx.LineTo(x+width, y+width*0.3) ctx.Stroke() y += 10 } }
func drawButton(ctx *nanovgo.Context, preicon int, text string, x, y, w, h float32, col nanovgo.Color) { var cornerRadius float32 = 4.0 var iw float32 var alpha uint8 if isBlack(col) { alpha = 16 } else { alpha = 32 } bg := nanovgo.LinearGradient(x, y, x, y+h, nanovgo.RGBA(255, 255, 255, alpha), nanovgo.RGBA(0, 0, 0, alpha)) ctx.BeginPath() ctx.RoundedRect(x+1, y+1, w-2, h-2, cornerRadius-1) if !isBlack(col) { ctx.SetFillColor(col) ctx.Fill() } ctx.SetFillPaint(bg) ctx.Fill() ctx.BeginPath() ctx.RoundedRect(x+0.5, y+0.5, w-1, h-1, cornerRadius-0.5) ctx.SetStrokeColor(nanovgo.RGBA(0, 0, 0, 48)) ctx.Stroke() ctx.SetFontSize(20.0) ctx.SetFontFace("sans-bold") tw, _ := ctx.TextBounds(0, 0, text) if preicon != 0 { ctx.SetFontSize(h * 1.3) ctx.SetFontFace("icons") iw, _ = ctx.TextBounds(0, 0, cpToUTF8(preicon)) iw += h * 0.15 ctx.SetFillColor(nanovgo.RGBA(255, 255, 255, 96)) ctx.SetTextAlign(nanovgo.AlignLeft | nanovgo.AlignMiddle) ctx.Text(x+w*0.5-tw*0.5-iw*0.75, y+h*0.5, cpToUTF8(preicon)) } ctx.SetFontSize(20.0) ctx.SetFontFace("sans-bold") ctx.SetTextAlign(nanovgo.AlignLeft | nanovgo.AlignMiddle) ctx.SetFillColor(nanovgo.RGBA(0, 0, 0, 160)) ctx.Text(x+w*0.5-tw*0.5+iw*0.25, y+h*0.5-1, text) ctx.SetFillColor(nanovgo.RGBA(255, 255, 255, 160)) ctx.Text(x+w*0.5-tw*0.5+iw*0.25, y+h*0.5, text) }
func drawWindow(ctx *nanovgo.Context, title string, x, y, w, h float32) { var cornerRadius float32 = 3.0 ctx.Save() defer ctx.Restore() // ctx.Reset(); // Window ctx.BeginPath() ctx.RoundedRect(x, y, w, h, cornerRadius) ctx.SetFillColor(nanovgo.RGBA(28, 30, 34, 192)) // ctx.FillColor(nanovgo.RGBA(0,0,0,128)); ctx.Fill() // Drop shadow shadowPaint := nanovgo.BoxGradient(x, y+2, w, h, cornerRadius*2, 10, nanovgo.RGBA(0, 0, 0, 128), nanovgo.RGBA(0, 0, 0, 0)) ctx.BeginPath() ctx.Rect(x-10, y-10, w+20, h+30) ctx.RoundedRect(x, y, w, h, cornerRadius) ctx.PathWinding(nanovgo.Hole) ctx.SetFillPaint(shadowPaint) ctx.Fill() // Header headerPaint := nanovgo.LinearGradient(x, y, x, y+15, nanovgo.RGBA(255, 255, 255, 8), nanovgo.RGBA(0, 0, 0, 16)) ctx.BeginPath() ctx.RoundedRect(x+1, y+1, w-2, 30, cornerRadius-1) ctx.SetFillPaint(headerPaint) ctx.Fill() ctx.BeginPath() ctx.MoveTo(x+0.5, y+0.5+30) ctx.LineTo(x+0.5+w-1, y+0.5+30) ctx.SetStrokeColor(nanovgo.RGBA(0, 0, 0, 32)) ctx.Stroke() ctx.SetFontSize(18.0) ctx.SetFontFace("sans-bold") ctx.SetTextAlign(nanovgo.AlignCenter | nanovgo.AlignMiddle) ctx.SetFontBlur(2) ctx.SetFillColor(nanovgo.RGBA(0, 0, 0, 128)) ctx.Text(x+w/2, y+16+1, title) ctx.SetFontBlur(0) ctx.SetFillColor(nanovgo.RGBA(220, 220, 220, 160)) ctx.Text(x+w/2, y+16, title) }
func (i *ImagePanel) Draw(self Widget, ctx *nanovgo.Context) { cols, _ := i.gridSize() x := float32(i.x) y := float32(i.y) thumbSize := float32(i.thumbSize) for j, image := range i.images { pX := x + float32(i.margin+(j%cols)*(i.thumbSize+i.spacing)) pY := y + float32(i.margin+(j/cols)*(i.thumbSize+i.spacing)) imgW, imgH, _ := ctx.ImageSize(image.ImageID) var iw, ih, ix, iy float32 if imgW < imgH { iw = thumbSize ih = iw * float32(imgH) / float32(imgW) ix = 0 iy = -(ih - thumbSize) * 0.5 } else { ih = thumbSize iw = ih * float32(imgH) / float32(imgW) iy = 0 ix = -(iw - thumbSize) * 0.5 } imgPaint := nanovgo.ImagePattern(pX+ix, pY+iy, iw, ih, 0, image.ImageID, toF(i.mouseIndex == j, 1.0, 0.7)) ctx.BeginPath() ctx.RoundedRect(pX, pY, thumbSize, thumbSize, 5) ctx.SetFillPaint(imgPaint) ctx.Fill() shadowPaint := nanovgo.BoxGradient(pX-1, pY, thumbSize+2, thumbSize+2, 5, 3, nanovgo.MONO(0, 128), nanovgo.MONO(0, 0)) ctx.BeginPath() ctx.Rect(pX-5, pY-5, thumbSize+10, thumbSize+10) ctx.RoundedRect(pX, pY, thumbSize, thumbSize, 6) ctx.PathWinding(nanovgo.Hole) ctx.SetFillPaint(shadowPaint) ctx.Fill() ctx.BeginPath() ctx.RoundedRect(pX+0.5, pY+0.5, thumbSize-1, thumbSize-1, 4-0.5) ctx.SetStrokeWidth(1.0) ctx.SetStrokeColor(nanovgo.MONO(255, 80)) ctx.Stroke() } }
// Draw() draws the widget (and all child widgets) func (w *WidgetImplement) Draw(self Widget, ctx *nanovgo.Context) { if debugFlag { ctx.SetStrokeWidth(1.0) ctx.BeginPath() ctx.Rect(float32(w.x)-0.5, float32(w.y)-0.5, float32(w.w)+1.0, float32(w.h)+1.0) ctx.SetStrokeColor(nanovgo.RGBA(255, 0, 0, 255)) ctx.Stroke() } if len(w.children) == 0 { return } ctx.Translate(float32(w.x), float32(w.y)) // draw depth 0 items var drawLater widgetsAsc = make([]Widget, 0, len(w.children)) for _, child := range w.children { if child.Visible() { depth := child.Depth() if depth == 0 { cx, cy := child.Position() cw, ch := child.Size() if !self.IsClipped(cx, cy, cw, ch) { child.Draw(child, ctx) } } else { drawLater = append(drawLater, child) } } } // draw by depth order sort.Sort(drawLater) for _, child := range drawLater { cx, cy := child.Position() cw, ch := child.Size() if !self.IsClipped(cx, cy, cw, ch) { child.Draw(child, ctx) } } ctx.Translate(-float32(w.x), -float32(w.y)) }
func drawSlider(ctx *nanovgo.Context, pos, x, y, w, h float32) { cy := y + float32(int(h*0.5)) kr := float32(int(h * 0.25)) ctx.Save() defer ctx.Restore() // ctx.ClearState(vg); // Slot bg := nanovgo.BoxGradient(x, cy-2+1, w, 4, 2, 2, nanovgo.RGBA(0, 0, 0, 32), nanovgo.RGBA(0, 0, 0, 128)) ctx.BeginPath() ctx.RoundedRect(x, cy-2, w, 4, 2) ctx.SetFillPaint(bg) ctx.Fill() // Knob Shadow bg = nanovgo.RadialGradient(x+float32(int(pos*w)), cy+1, kr-3, kr+3, nanovgo.RGBA(0, 0, 0, 64), nanovgo.RGBA(0, 0, 0, 0)) ctx.BeginPath() ctx.Rect(x+float32(int(pos*w))-kr-5, cy-kr-5, kr*2+5+5, kr*2+5+5+3) ctx.Circle(x+float32(int(pos*w)), cy, kr) ctx.PathWinding(nanovgo.Hole) ctx.SetFillPaint(bg) ctx.Fill() // Knob knob := nanovgo.LinearGradient(x, cy-kr, x, cy+kr, nanovgo.RGBA(255, 255, 255, 16), nanovgo.RGBA(0, 0, 0, 16)) ctx.BeginPath() ctx.Circle(x+float32(int(pos*w)), cy, kr-1) ctx.SetFillColor(nanovgo.RGBA(40, 43, 48, 255)) ctx.Fill() ctx.SetFillPaint(knob) ctx.Fill() ctx.BeginPath() ctx.Circle(x+float32(int(pos*w)), cy, kr-0.5) ctx.SetStrokeColor(nanovgo.RGBA(0, 0, 0, 92)) ctx.Stroke() }
func (t *TextBox) Draw(self Widget, ctx *nanovgo.Context) { t.WidgetImplement.Draw(self, ctx) x := float32(t.x) y := float32(t.y) w := float32(t.w) h := float32(t.h) bg := nanovgo.BoxGradient(x+1, y+2, w-2, h-2, 3, 4, nanovgo.MONO(255, 32), nanovgo.MONO(32, 32)) fg1 := nanovgo.BoxGradient(x+1, y+2, w-2, h-2, 3, 4, nanovgo.MONO(150, 32), nanovgo.MONO(32, 32)) fg2 := nanovgo.BoxGradient(x+1, y+2, w-2, h-2, 3, 4, nanovgo.RGBA(255, 0, 0, 100), nanovgo.RGBA(255, 0, 0, 50)) ctx.BeginPath() ctx.RoundedRect(x+1, y+2, w-2, h-2, 3) if t.editable && t.Focused() { if t.validFormat { ctx.SetFillPaint(fg1) } else { ctx.SetFillPaint(fg2) } } else { ctx.SetFillPaint(bg) } ctx.Fill() ctx.BeginPath() ctx.RoundedRect(x+0.5, y+0.5, w-1, h-1, 2.5) ctx.SetStrokeColor(nanovgo.MONO(0, 48)) ctx.Stroke() ctx.SetFontSize(float32(t.FontSize())) ctx.SetFontFace(t.Font()) drawPosX := x drawPosY := y + h*0.5 + 1 xSpacing := h * 0.3 var unitWidth float32 if t.unitImage > 0 { iw, ih, _ := ctx.ImageSize(t.unitImage) unitHeight := float32(ih) * 0.4 unitWidth = float32(iw) * unitHeight / float32(h) imgPaint := nanovgo.ImagePattern(x+w-xSpacing-unitWidth, drawPosY-unitHeight*0.5, unitWidth, unitHeight, 0, t.unitImage, toF(t.enabled, 0.7, 0.35)) ctx.BeginPath() ctx.Rect(x+w-xSpacing-unitWidth, drawPosY-unitHeight*0.5, unitWidth, unitHeight) ctx.SetFillPaint(imgPaint) ctx.Fill() unitWidth += 2 } else if t.units != "" { unitWidth, _ = ctx.TextBounds(0, 0, t.units) ctx.SetFillColor(nanovgo.MONO(255, toB(t.enabled, 64, 32))) ctx.SetTextAlign(nanovgo.AlignRight | nanovgo.AlignMiddle) ctx.Text(x+w-xSpacing, drawPosY, t.units) } switch t.alignment { case TextLeft: ctx.SetTextAlign(nanovgo.AlignLeft | nanovgo.AlignMiddle) drawPosX += xSpacing case TextRight: ctx.SetTextAlign(nanovgo.AlignRight | nanovgo.AlignMiddle) drawPosX += w - unitWidth - xSpacing case TextCenter: ctx.SetTextAlign(nanovgo.AlignCenter | nanovgo.AlignMiddle) drawPosX += w * 0.5 } if t.enabled { ctx.SetFillColor(t.theme.TextColor) } else { ctx.SetFillColor(t.theme.DisabledTextColor) } // clip visible text area clipX := x + xSpacing - 1 clipY := y + 1.0 clipWidth := w - unitWidth - 2.0*xSpacing + 2.0 clipHeight := h - 3.0 ctx.Scissor(clipX, clipY, clipWidth, clipHeight) oldDrawPosX := drawPosX drawPosX += t.textOffset if t.committed { ctx.Text(drawPosX, drawPosY, t.value) } else { text := t.editingText() textString := string(text) _, bounds := ctx.TextBounds(drawPosX, drawPosY, textString) lineH := bounds[3] - bounds[1] // find cursor positions glyphs := ctx.TextGlyphPositionsRune(drawPosX, drawPosY, text) t.updateCursor(ctx, bounds[2], glyphs) // compute text offset prevCPos := toI(t.cursorPos > 0, t.cursorPos-1, 0) nextCPos := toI(t.cursorPos < len(glyphs), t.cursorPos+1, len(glyphs)) prevCX := t.textIndex2Position(prevCPos, bounds[2], glyphs) nextCX := t.textIndex2Position(nextCPos, bounds[2], glyphs) if nextCX > clipX+clipWidth { t.textOffset -= nextCX - (clipX + clipWidth) + 1.0 } if prevCX < clipX { t.textOffset += clipX - prevCX + 1.0 } drawPosX = oldDrawPosX + t.textOffset // draw text with offset ctx.TextRune(drawPosX, drawPosY, text) _, bounds = ctx.TextBounds(drawPosX, drawPosY, textString) // recompute cursor position glyphs = ctx.TextGlyphPositionsRune(drawPosX, drawPosY, text) var caretX float32 = -1 if len(t.preeditText) != 0 { // draw preedit text caretX = t.textIndex2Position(t.cursorPos+len(t.preeditText), bounds[2], glyphs) offsetIndex := t.cursorPos offsetX := t.textIndex2Position(t.cursorPos, bounds[2], glyphs) ctx.SetStrokeColor(nanovgo.MONO(255, 160)) ctx.SetFillColor(nanovgo.MONO(255, 80)) ctx.SetStrokeWidth(2.0) for i, blockLength := range t.preeditBlocks { nextOffsetIndex := offsetIndex + blockLength nextOffsetX := t.textIndex2Position(nextOffsetIndex, bounds[2], glyphs) if i != t.preeditFocusedBlock { ctx.BeginPath() ctx.MoveTo(offsetX+2, drawPosY+lineH*0.5-1) ctx.LineTo(nextOffsetX-2, drawPosY+lineH*0.5-1) ctx.Stroke() } else { ctx.BeginPath() ctx.Rect(offsetX, drawPosY-lineH*0.5, nextOffsetX-offsetX, lineH) ctx.Fill() } offsetIndex = nextOffsetIndex offsetX = nextOffsetX } screen := t.FindWindow().Parent().(*Screen) oldCurX, oldCurY, oldCurH := screen.PreeditCursorPos() absX, absY := t.Parent().AbsolutePosition() newCurX := int(caretX) + absX newCurY := int(drawPosY+lineH*0.5) + absY newCurH := int(lineH) if oldCurX != newCurX || oldCurY != newCurY || oldCurH != newCurH { screen.SetPreeditCursorPos(newCurX, newCurY, newCurH) } } else if t.cursorPos > -1 { // regular cursor and selection area caretX = t.textIndex2Position(t.cursorPos, bounds[2], glyphs) if t.selectionPos > -1 { caretX2 := caretX selX := t.textIndex2Position(t.selectionPos, bounds[2], glyphs) if caretX2 > selX { selX, caretX2 = caretX2, selX } // draw selection ctx.BeginPath() ctx.SetFillColor(nanovgo.MONO(255, 80)) ctx.Rect(caretX2, drawPosY-lineH*0.5, selX-caretX2, lineH) ctx.Fill() } } if caretX > 0 { // draw cursor ctx.BeginPath() ctx.MoveTo(caretX, drawPosY-lineH*0.5) ctx.LineTo(caretX, drawPosY+lineH*0.5) ctx.SetStrokeColor(nanovgo.RGBA(255, 192, 0, 255)) ctx.SetStrokeWidth(1.0) ctx.Stroke() } } ctx.ResetScissor() }
func (c *ColorWheel) Draw(self Widget, ctx *nanovgo.Context) { c.WidgetImplement.Draw(self, ctx) if !c.visible { return } x := float32(c.x) y := float32(c.y) w := float32(c.w) h := float32(c.h) ctx.Save() defer ctx.Restore() cx := x + w*0.5 cy := y + h*0.5 r1 := toF(w < h, w, h)*0.5 - 5.0 r0 := r1 * 0.75 aeps := 0.7 / r1 // half a pixel arc length in radians (2pi cancels out). for i := 0; i < 6; i++ { a0 := float32(i)/6.0*nanovgo.PI*2.0 - aeps a1 := float32(i+1)/6.0*nanovgo.PI*2.0 + aeps ctx.BeginPath() ctx.Arc(cx, cy, r0, a0, a1, nanovgo.Clockwise) ctx.Arc(cx, cy, r1, a1, a0, nanovgo.CounterClockwise) ctx.ClosePath() sin1, cos1 := sinCosF(a0) sin2, cos2 := sinCosF(a1) ax := cx + cos1*(r0+r1)*0.5 ay := cy + sin1*(r0+r1)*0.5 bx := cx + cos2*(r0+r1)*0.5 by := cy + sin2*(r0+r1)*0.5 color1 := nanovgo.HSLA(a0/(nanovgo.PI*2), 1.0, 0.55, 255) color2 := nanovgo.HSLA(a1/(nanovgo.PI*2), 1.0, 0.55, 255) paint := nanovgo.LinearGradient(ax, ay, bx, by, color1, color2) ctx.SetFillPaint(paint) ctx.Fill() } ctx.BeginPath() ctx.Circle(cx, cy, r0-0.5) ctx.Circle(cx, cy, r1+0.5) ctx.SetStrokeColor(nanovgo.MONO(0, 64)) ctx.Stroke() // Selector ctx.Save() defer ctx.Restore() ctx.Translate(cx, cy) ctx.Rotate(c.hue * nanovgo.PI * 2) // Marker on u := clampF(r1/50, 1.5, 4.0) ctx.SetStrokeWidth(u) ctx.BeginPath() ctx.Rect(r0-1, -2*u, r1-r0+2, 4*u) ctx.SetStrokeColor(nanovgo.MONO(255, 192)) ctx.Stroke() paint := nanovgo.BoxGradient(r0-3, -5, r1-r0+6, 10, 2, 4, nanovgo.MONO(0, 128), nanovgo.MONO(0, 0)) ctx.BeginPath() ctx.Rect(r0-2-10, -4-10, r1-r0+4+20, 8+20) ctx.Rect(r0-2, -4, r1-r0+4, 8) ctx.PathWinding(nanovgo.Hole) ctx.SetFillPaint(paint) ctx.Fill() // Center triangle r := r0 - 6 sin1, cos1 := sinCosF(120.0 / 180.0 * nanovgo.PI) sin2, cos2 := sinCosF(-120.0 / 180.0 * nanovgo.PI) ax := cos1 * r ay := sin1 * r bx := cos2 * r by := sin2 * r ctx.BeginPath() ctx.MoveTo(r, 0) ctx.LineTo(ax, ay) ctx.LineTo(bx, by) ctx.ClosePath() triPaint1 := nanovgo.LinearGradient(r, 0, ax, ay, nanovgo.HSL(c.hue, 1.0, 0.5), nanovgo.MONO(255, 255)) ctx.SetFillPaint(triPaint1) ctx.Fill() triPaint2 := nanovgo.LinearGradient((r+ax)*0.5, ay*0.5, bx, by, nanovgo.MONO(0, 0), nanovgo.MONO(0, 255)) ctx.SetFillPaint(triPaint2) ctx.Fill() // selector circle on triangle px, py := c.calculatePosition() ctx.SetStrokeWidth(u) ctx.BeginPath() ctx.Circle(px, py, 2*u) ctx.SetStrokeColor(nanovgo.MONO(255, 192)) ctx.Stroke() }
func drawGraph(ctx *nanovgo.Context, x, y, w, h, t float32) { var sx, sy [6]float32 dx := w / 5.0 samples := []float32{ (1 + sinF(t*1.2345+cosF(t*0.33457)*0.44)) * 0.5, (1 + sinF(t*0.68363+cosF(t*1.3)*1.55)) * 0.5, (1 + sinF(t*1.1642+cosF(t*0.33457)*1.24)) * 0.5, (1 + sinF(t*0.56345+cosF(t*1.63)*0.14)) * 0.5, (1 + sinF(t*1.6245+cosF(t*0.254)*0.3)) * 0.5, (1 + sinF(t*0.345+cosF(t*0.03)*0.6)) * 0.5, } for i := 0; i < 6; i++ { sx[i] = x + float32(i)*dx sy[i] = y + h*samples[i]*0.8 } // Graph background bg := nanovgo.LinearGradient(x, y, x, y+h, nanovgo.RGBA(0, 160, 192, 0), nanovgo.RGBA(0, 160, 192, 64)) ctx.BeginPath() ctx.MoveTo(sx[0], sy[0]) for i := 1; i < 6; i++ { ctx.BezierTo(sx[i-1]+dx*0.5, sy[i-1], sx[i]-dx*0.5, sy[i], sx[i], sy[i]) } ctx.LineTo(x+w, y+h) ctx.LineTo(x, y+h) ctx.SetFillPaint(bg) ctx.Fill() // Graph line ctx.BeginPath() ctx.MoveTo(sx[0], sy[0]+2) for i := 1; i < 6; i++ { ctx.BezierTo(sx[i-1]+dx*0.5, sy[i-1]+2, sx[i]-dx*0.5, sy[i]+2, sx[i], sy[i]+2) } ctx.SetStrokeColor(nanovgo.RGBA(0, 0, 0, 32)) ctx.SetStrokeWidth(3.0) ctx.Stroke() ctx.BeginPath() ctx.MoveTo(sx[0], sy[0]) for i := 1; i < 6; i++ { ctx.BezierTo(sx[i-1]+dx*0.5, sy[i-1], sx[i]-dx*0.5, sy[i], sx[i], sy[i]) } ctx.SetStrokeColor(nanovgo.RGBA(0, 160, 192, 255)) ctx.SetStrokeWidth(3.0) ctx.Stroke() // Graph sample pos for i := 0; i < 6; i++ { bg = nanovgo.RadialGradient(sx[i], sy[i]+2, 3.0, 8.0, nanovgo.RGBA(0, 0, 0, 32), nanovgo.RGBA(0, 0, 0, 0)) ctx.BeginPath() ctx.Rect(sx[i]-10, sy[i]-10+2, 20, 20) ctx.SetFillPaint(bg) ctx.Fill() } ctx.BeginPath() for i := 0; i < 6; i++ { ctx.Circle(sx[i], sy[i], 4.0) } ctx.SetFillColor(nanovgo.RGBA(0, 160, 192, 255)) ctx.Fill() ctx.BeginPath() for i := 0; i < 6; i++ { ctx.Circle(sx[i], sy[i], 2.0) } ctx.SetFillColor(nanovgo.RGBA(220, 220, 220, 255)) ctx.Fill() ctx.SetStrokeWidth(1.0) }
func drawThumbnails(ctx *nanovgo.Context, x, y, w, h float32, images []int, t float32) { var cornerRadius float32 = 3.0 var thumb float32 = 60.0 var arry float32 = 30.5 stackh := float32(len(images)/2)*(thumb+10) + 10 u := (1 + cosF(t*0.5)) * 0.5 u2 := (1 - cosF(t*0.2)) * 0.5 ctx.Save() defer ctx.Restore() // Drop shadow shadowPaint := nanovgo.BoxGradient(x, y+4, w, h, cornerRadius*2, 20, nanovgo.RGBA(0, 0, 0, 128), nanovgo.RGBA(0, 0, 0, 0)) ctx.BeginPath() ctx.Rect(x-10, y-10, w+20, h+30) ctx.RoundedRect(x, y, w, h, cornerRadius) ctx.PathWinding(nanovgo.Hole) ctx.SetFillPaint(shadowPaint) ctx.Fill() // Window ctx.BeginPath() ctx.RoundedRect(x, y, w, h, cornerRadius) ctx.MoveTo(x-10, y+arry) ctx.LineTo(x+1, y+arry-11) ctx.LineTo(x+1, y+arry+11) ctx.SetFillColor(nanovgo.RGBA(200, 200, 200, 255)) ctx.Fill() ctx.Block(func() { ctx.Scissor(x, y, w, h) ctx.Translate(0, -(stackh-h)*u) dv := 1.0 / float32(len(images)-1) for i, imageID := range images { tx := x + 10.0 ty := y + 10.0 tx += float32(i%2) * (thumb + 10.0) ty += float32(i/2) * (thumb + 10.0) imgW, imgH, _ := ctx.ImageSize(imageID) var iw, ih, ix, iy float32 if imgW < imgH { iw = thumb ih = iw * float32(imgH) / float32(imgW) ix = 0 iy = -(ih - thumb) * 0.5 } else { ih = thumb iw = ih * float32(imgW) / float32(imgH) ix = -(iw - thumb) * 0.5 iy = 0 } v := float32(i) * dv a := clampF((u2-v)/dv, 0, 1) if a < 1.0 { drawSpinner(ctx, tx+thumb/2, ty+thumb/2, thumb*0.25, t) } imgPaint := nanovgo.ImagePattern(tx+ix, ty+iy, iw, ih, 0.0/180.0*nanovgo.PI, imageID, a) ctx.BeginPath() ctx.RoundedRect(tx, ty, thumb, thumb, 5) ctx.SetFillPaint(imgPaint) ctx.Fill() shadowPaint := nanovgo.BoxGradient(tx-1, ty, thumb+2, thumb+2, 5, 3, nanovgo.RGBA(0, 0, 0, 128), nanovgo.RGBA(0, 0, 0, 0)) ctx.BeginPath() ctx.Rect(tx-5, ty-5, thumb+10, thumb+10) ctx.RoundedRect(tx, ty, thumb, thumb, 6) ctx.PathWinding(nanovgo.Hole) ctx.SetFillPaint(shadowPaint) ctx.Fill() ctx.BeginPath() ctx.RoundedRect(tx+0.5, ty+0.5, thumb-1, thumb-1, 4-0.5) ctx.SetStrokeWidth(1.0) ctx.SetStrokeColor(nanovgo.RGBA(255, 255, 255, 192)) ctx.Stroke() } }) // Hide fades fadePaint := nanovgo.LinearGradient(x, y, x, y+6, nanovgo.RGBA(200, 200, 200, 255), nanovgo.RGBA(200, 200, 200, 0)) ctx.BeginPath() ctx.Rect(x+4, y, w-8, 6) ctx.SetFillPaint(fadePaint) ctx.Fill() fadePaint = nanovgo.LinearGradient(x, y+h, x, y+h-6, nanovgo.RGBA(200, 200, 200, 255), nanovgo.RGBA(200, 200, 200, 0)) ctx.BeginPath() ctx.Rect(x+4, y+h-6, w-8, 6) ctx.SetFillPaint(fadePaint) ctx.Fill() // Scroll bar shadowPaint = nanovgo.BoxGradient(x+w-12+1, y+4+1, 8, h-8, 3, 4, nanovgo.RGBA(0, 0, 0, 32), nanovgo.RGBA(0, 0, 0, 92)) ctx.BeginPath() ctx.RoundedRect(x+w-12, y+4, 8, h-8, 3) ctx.SetFillPaint(shadowPaint) // ctx.FillColor(ctx.RGBA(255,0,0,128)); ctx.Fill() scrollH := (h / stackh) * (h - 8) shadowPaint = nanovgo.BoxGradient(x+w-12-1, y+4+(h-8-scrollH)*u-1, 8, scrollH, 3, 4, nanovgo.RGBA(220, 220, 220, 255), nanovgo.RGBA(128, 128, 128, 255)) ctx.BeginPath() ctx.RoundedRect(x+w-12+1, y+4+1+(h-8-scrollH)*u, 8-2, scrollH-2, 2) ctx.SetFillPaint(shadowPaint) // ctx.FillColor(ctx.RGBA(0,0,0,128)); ctx.Fill() }
func drawColorWheel(ctx *nanovgo.Context, x, y, w, h, t float32) { var r0, r1, ax, ay, bx, by, aeps, r float32 hue := sinF(t * 0.12) ctx.Save() defer ctx.Restore() /* ctx.BeginPath() ctx.Rect(x,y,w,h) ctx.FillColor(nanovgo.RGBA(255,0,0,128)) ctx.Fill()*/ cx := x + w*0.5 cy := y + h*0.5 if w < h { r1 = w*0.5 - 5.0 } else { r1 = h*0.5 - 5.0 } r0 = r1 - 20.0 aeps = 0.5 / r1 // half a pixel arc length in radians (2pi cancels out). for i := 0; i < 6; i++ { a0 := float32(i)/6.0*nanovgo.PI*2.0 - aeps a1 := float32(i+1.0)/6.0*nanovgo.PI*2.0 + aeps ctx.BeginPath() ctx.Arc(cx, cy, r0, a0, a1, nanovgo.Clockwise) ctx.Arc(cx, cy, r1, a1, a0, nanovgo.CounterClockwise) ctx.ClosePath() ax = cx + cosF(a0)*(r0+r1)*0.5 ay = cy + sinF(a0)*(r0+r1)*0.5 bx = cx + cosF(a1)*(r0+r1)*0.5 by = cy + sinF(a1)*(r0+r1)*0.5 paint := nanovgo.LinearGradient(ax, ay, bx, by, nanovgo.HSLA(a0/(nanovgo.PI*2), 1.0, 0.55, 255), nanovgo.HSLA(a1/(nanovgo.PI*2), 1.0, 0.55, 255)) ctx.SetFillPaint(paint) ctx.Fill() } ctx.BeginPath() ctx.Circle(cx, cy, r0-0.5) ctx.Circle(cx, cy, r1+0.5) ctx.SetStrokeColor(nanovgo.RGBA(0, 0, 0, 64)) ctx.SetStrokeWidth(1.0) ctx.Stroke() // Selector ctx.Translate(cx, cy) ctx.Rotate(hue * nanovgo.PI * 2) // Marker on ctx.SetStrokeWidth(2.0) ctx.BeginPath() ctx.Rect(r0-1, -3, r1-r0+2, 6) ctx.SetStrokeColor(nanovgo.RGBA(255, 255, 255, 192)) ctx.Stroke() paint := nanovgo.BoxGradient(r0-3, -5, r1-r0+6, 10, 2, 4, nanovgo.RGBA(0, 0, 0, 128), nanovgo.RGBA(0, 0, 0, 0)) ctx.BeginPath() ctx.Rect(r0-2-10, -4-10, r1-r0+4+20, 8+20) ctx.Rect(r0-2, -4, r1-r0+4, 8) ctx.PathWinding(nanovgo.Hole) ctx.SetFillPaint(paint) ctx.Fill() // Center triangle r = r0 - 6 ax = cosF(120.0/180.0*nanovgo.PI) * r ay = sinF(120.0/180.0*nanovgo.PI) * r bx = cosF(-120.0/180.0*nanovgo.PI) * r by = sinF(-120.0/180.0*nanovgo.PI) * r ctx.BeginPath() ctx.MoveTo(r, 0) ctx.LineTo(ax, ay) ctx.LineTo(bx, by) ctx.ClosePath() paint = nanovgo.LinearGradient(r, 0, ax, ay, nanovgo.HSLA(hue, 1.0, 0.5, 255), nanovgo.RGBA(255, 255, 255, 255)) ctx.SetFillPaint(paint) ctx.Fill() paint = nanovgo.LinearGradient((r+ax)*0.5, (0+ay)*0.5, bx, by, nanovgo.RGBA(0, 0, 0, 0), nanovgo.RGBA(0, 0, 0, 255)) ctx.SetFillPaint(paint) ctx.Fill() ctx.SetStrokeColor(nanovgo.RGBA(0, 0, 0, 64)) ctx.Stroke() // Select circle on triangle ax = cosF(120.0/180.0*nanovgo.PI) * r * 0.3 ay = sinF(120.0/180.0*nanovgo.PI) * r * 0.4 ctx.SetStrokeWidth(2.0) ctx.BeginPath() ctx.Circle(ax, ay, 5) ctx.SetStrokeColor(nanovgo.RGBA(255, 255, 255, 192)) ctx.Stroke() paint = nanovgo.RadialGradient(ax, ay, 7, 9, nanovgo.RGBA(0, 0, 0, 64), nanovgo.RGBA(0, 0, 0, 0)) ctx.BeginPath() ctx.Rect(ax-20, ay-20, 40, 40) ctx.Circle(ax, ay, 7) ctx.PathWinding(nanovgo.Hole) ctx.SetFillPaint(paint) ctx.Fill() }
func (w *Window) Draw(self Widget, ctx *nanovgo.Context) { ds := float32(w.theme.WindowDropShadowSize) cr := float32(w.theme.WindowCornerRadius) hh := float32(w.theme.WindowHeaderHeight) // Draw window wx := float32(w.x) wy := float32(w.y) ww := float32(w.w) wh := float32(w.h) ctx.Save() ctx.BeginPath() ctx.RoundedRect(wx, wy, ww, wh, cr) if w.mouseFocus { ctx.SetFillColor(w.theme.WindowFillFocused) } else { ctx.SetFillColor(w.theme.WindowFillUnfocused) } ctx.Fill() // Draw a drop shadow shadowPaint := nanovgo.BoxGradient(wx, wy, ww, wh, cr*2, ds*2, w.theme.DropShadow, w.theme.Transparent) ctx.BeginPath() ctx.Rect(wx-ds, wy-ds, ww+ds*2, wh+ds*2) ctx.RoundedRect(wx, wy, ww, wh, cr) ctx.PathWinding(nanovgo.Hole) ctx.SetFillPaint(shadowPaint) ctx.Fill() if w.title != "" { headerPaint := nanovgo.LinearGradient(wx, wy, ww, wh+hh, w.theme.WindowHeaderGradientTop, w.theme.WindowHeaderGradientBot) ctx.BeginPath() ctx.RoundedRect(wx, wy, ww, hh, cr) ctx.SetFillPaint(headerPaint) ctx.Fill() ctx.BeginPath() ctx.RoundedRect(wx, wy, ww, wh, cr) ctx.SetStrokeColor(w.theme.WindowHeaderSepTop) ctx.Scissor(wx, wy, ww, 0.5) ctx.Stroke() ctx.ResetScissor() ctx.BeginPath() ctx.MoveTo(wx+0.5, wy+hh-1.5) ctx.LineTo(wx+ww-0.5, wy+hh-1.5) ctx.SetStrokeColor(w.theme.WindowHeaderSepTop) ctx.Stroke() ctx.SetFontSize(18.0) ctx.SetFontFace(w.theme.FontBold) ctx.SetTextAlign(nanovgo.AlignCenter | nanovgo.AlignMiddle) ctx.SetFontBlur(2.0) ctx.SetFillColor(w.theme.DropShadow) ctx.Text(wx+ww*0.5, wy+hh*0.5, w.title) ctx.SetFontBlur(0.0) if w.focused { ctx.SetFillColor(w.theme.WindowTitleFocused) } else { ctx.SetFillColor(w.theme.WindowTitleUnfocused) } ctx.Text(wx+ww*0.5, wy+hh*0.5-1, w.title) } ctx.Restore() w.WidgetImplement.Draw(self, ctx) }
func (b *Button) Draw(self Widget, ctx *nanovgo.Context) { b.WidgetImplement.Draw(self, ctx) bx := float32(b.x) by := float32(b.y) bw := float32(b.w) bh := float32(b.h) var gradTop nanovgo.Color var gradBot nanovgo.Color if b.pushed { gradTop = b.theme.ButtonGradientTopPushed gradBot = b.theme.ButtonGradientBotPushed } else if b.mouseFocus && b.enabled { gradTop = b.theme.ButtonGradientTopFocused gradBot = b.theme.ButtonGradientBotFocused } else { gradTop = b.theme.ButtonGradientTopUnfocused gradBot = b.theme.ButtonGradientBotUnfocused } ctx.BeginPath() ctx.RoundedRect(bx+1.0, by+1.0, bw-2.0, bh-2.0, float32(b.theme.ButtonCornerRadius-1)) if b.backgroundColor.A != 0.0 { bgColor := b.backgroundColor bgColor.A = 1.0 ctx.SetFillColor(bgColor) ctx.Fill() if b.pushed { gradTop.A = 0.8 gradBot.A = 0.8 } else { a := 1 - b.backgroundColor.A if !b.enabled { a = a*0.5 + 0.5 } gradTop.A = a gradBot.A = a } } bg := nanovgo.LinearGradient(bx, by, bx, by+bh, gradTop, gradBot) ctx.SetFillPaint(bg) ctx.Fill() ctx.BeginPath() var pOff float32 = 0.0 if b.pushed { pOff = 1.0 } ctx.RoundedRect(bx+0.5, by+1.5-pOff, bw-1.0, bh-2+pOff, float32(b.theme.ButtonCornerRadius)) ctx.SetStrokeColor(b.theme.BorderLight) ctx.Stroke() ctx.BeginPath() ctx.RoundedRect(bx+0.5, by+0.5, bw-1.0, bh-2, float32(b.theme.ButtonCornerRadius)) ctx.SetStrokeColor(b.theme.BorderDark) ctx.Stroke() fontSize := float32(b.FontSize()) ctx.SetFontSize(fontSize) ctx.SetFontFace(b.theme.FontBold) caption := b.caption tw, _ := ctx.TextBounds(0, 0, caption) centerX := bx + bw*0.5 centerY := by + bh*0.5 textPosX := centerX - tw*0.5 textPosY := centerY - 1.0 textColor := b.TextColor() if b.icon > 0 || b.imageIcon > 0 { var iw, ih float32 if b.icon > 0 { ih = fontSize * 1.5 / 2 ctx.SetFontSize(ih) ctx.SetFontFace(b.theme.FontIcons) iw, _ = ctx.TextBounds(0, 0, string([]rune{rune(b.icon)})) } else if b.imageIcon > 0 { ih = fontSize * 0.9 w, h, _ := ctx.ImageSize(b.imageIcon) iw = float32(w) * ih / float32(h) } if b.caption != "" { iw += float32(b.h) * 0.15 } ctx.SetFillColor(textColor) ctx.SetTextAlign(nanovgo.AlignLeft | nanovgo.AlignMiddle) iconPosX := centerX iconPosY := centerY - 1 switch b.iconPosition { case ButtonIconLeftCentered: iconPosX -= (tw + iw) * 0.5 textPosX += iw * 0.5 case ButtonIconRightCentered: iconPosX -= iw * 0.5 textPosX += tw * 0.5 case ButtonIconLeft: iconPosX = bx + 8.0 case ButtonIconRight: iconPosX = bx + bw - iw - 8 } if b.icon > 0 { ctx.TextRune(iconPosX, iconPosY, []rune{rune(b.icon)}) } else { var eOff float32 = 0.25 if b.enabled { eOff = 0.5 } imgPaint := nanovgo.ImagePattern(iconPosX, iconPosY-ih*0.5, iw, ih, 0, b.imageIcon, eOff) ctx.SetFillPaint(imgPaint) ctx.Fill() } } ctx.SetFontSize(fontSize) ctx.SetFontFace(b.theme.FontBold) ctx.SetTextAlign(nanovgo.AlignLeft | nanovgo.AlignMiddle) ctx.SetFillColor(b.theme.TextColorShadow) ctx.Text(textPosX, textPosY, caption) ctx.SetFillColor(textColor) ctx.Text(textPosX, textPosY+1.0, caption) }