func drawScissor(ctx *nanovgo.Context, x, y, t float32) { ctx.Save() // Draw first rect and set scissor to it's area. ctx.Translate(x, y) ctx.Rotate(nanovgo.DegToRad(5)) ctx.BeginPath() ctx.Rect(-20, -20, 60, 40) ctx.SetFillColor(nanovgo.RGBA(255, 0, 0, 255)) ctx.Fill() ctx.Scissor(-20, -20, 60, 40) // Draw second rectangle with offset and rotation. ctx.Translate(40, 0) ctx.Rotate(t) // Draw the intended second rectangle without any scissoring. ctx.Save() ctx.ResetScissor() ctx.BeginPath() ctx.Rect(-20, -10, 60, 30) ctx.SetFillColor(nanovgo.RGBA(255, 128, 0, 64)) ctx.Fill() ctx.Restore() // Draw second rectangle with combined scissoring. ctx.IntersectScissor(-20, -10, 60, 30) ctx.BeginPath() ctx.Rect(-20, -10, 60, 30) ctx.SetFillColor(nanovgo.RGBA(255, 128, 0, 255)) ctx.Fill() ctx.Restore() }
func (v *VScrollPanel) Draw(self Widget, ctx *nanovgo.Context) { if len(v.children) == 0 { return } x := float32(v.x) y := float32(v.y) w := float32(v.w) h := float32(v.h) child := v.children[0] layout := self.Layout() if layout != nil { _, v.childPreferredHeight = layout.PreferredSize(self, ctx) } else { _, v.childPreferredHeight = child.PreferredSize(child, ctx) } ctx.Save() ctx.Translate(x, y) ctx.Scissor(0, 0, w, h) ctx.Translate(0, -v.scroll*(float32(v.childPreferredHeight)-h)) if child.Visible() { child.Draw(child, ctx) } ctx.Restore() if v.childPreferredHeight > v.h { scrollH := h * minF(1.0, h/float32(v.childPreferredHeight)) scrollH = minF(maxF(20.0, scrollH), h) paint := nanovgo.BoxGradient(x+w-12+1, y+4+1, 8, h-8, 3, 4, nanovgo.MONO(0, 32), nanovgo.MONO(0, 92)) ctx.BeginPath() ctx.RoundedRect(x+w-12, y+4, 8, h-8, 3) ctx.SetFillPaint(paint) ctx.Fill() barPaint := nanovgo.BoxGradient(x+y-12-1, y+4+1+(h-8-scrollH)*v.scroll-1, 8, scrollH, 3, 4, nanovgo.MONO(220, 100), nanovgo.MONO(128, 100)) ctx.BeginPath() ctx.RoundedRect(x+w-12+1, y+4+1+(h-8-scrollH)*v.scroll, 8-2, scrollH-2, 2) ctx.SetFillPaint(barPaint) 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 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 (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() }