func loadImageDirectory(ctx *nanovgo.Context, dir string) []nanogui.Image { var images []nanogui.Image files, err := ioutil.ReadDir(dir) if err != nil { panic(fmt.Sprintf("loadImageDirectory: read error %v\n", err)) } for _, file := range files { if file.IsDir() { continue } ext := path.Ext(file.Name()) if ext != ".png" { continue } fullPath := path.Join(dir, file.Name()) img := ctx.CreateImage(fullPath, 0) if img == 0 { panic("Could not open image data!") } images = append(images, nanogui.Image{ ImageID: img, Name: fullPath[:len(fullPath)-4], }) } return images }
func (i *ImageView) PreferredSize(self Widget, ctx *nanovgo.Context) (int, int) { if i.image == 0 { return 0, 0 } w, h, _ := ctx.ImageSize(i.image) return w, h }
func drawLabel(ctx *nanovgo.Context, text string, x, y, w, h float32) { ctx.SetFontSize(18.0) ctx.SetFontFace("sans") ctx.SetFillColor(nanovgo.RGBA(255, 255, 255, 128)) ctx.SetTextAlign(nanovgo.AlignLeft | nanovgo.AlignMiddle) ctx.Text(x, y+h*0.5, text) }
func drawEditBox(ctx *nanovgo.Context, text string, x, y, w, h float32) { drawEditBoxBase(ctx, x, y, w, h) ctx.SetFontSize(20.0) ctx.SetFontFace("sans") ctx.SetFillColor(nanovgo.RGBA(255, 255, 255, 64)) ctx.SetTextAlign(nanovgo.AlignLeft | nanovgo.AlignMiddle) ctx.Text(x+h*0.3, y+h*0.5, text) }
func RenderDemo(ctx *nanovgo.Context, mx, my, width, height, t float32, blowup bool, data *DemoData) { drawEyes(ctx, width-250, 50, 150, 100, mx, my, t) drawParagraph(ctx, width-450, 50, 150, 100, mx, my) drawGraph(ctx, 0, height/2, width, height/2, t) drawColorWheel(ctx, width-300, height-300, 250.0, 250.0, t) // Line joints drawLines(ctx, 120, height-50, 600, 50, t) // Line widths drawWidths(ctx, 10, 50, 30) // Line caps drawCaps(ctx, 10, 300, 30) drawScissor(ctx, 50, height-80, t) ctx.Save() defer ctx.Restore() if blowup { ctx.Rotate(sinF(t*0.3) * 5.0 / 180.0 * nanovgo.PI) ctx.Scale(2.0, 2.0) } // Widgets drawWindow(ctx, "Widgets `n Stuff", 50, 50, 300, 400) var x float32 = 60.0 var y float32 = 95.0 drawSearchBox(ctx, "Search", x, y, 280, 25) y += 40 drawDropDown(ctx, "Effects", x, y, 280, 28) popy := y + 14 y += 45 // Form drawLabel(ctx, "Login", x, y, 280, 20) y += 25 drawEditBox(ctx, "Email", x, y, 280, 28) y += 35 drawEditBox(ctx, "Password", x, y, 280, 28) y += 38 drawCheckBox(ctx, "Remember me", x, y, 140, 28) drawButton(ctx, IconLOGIN, "Sign in", x+138, y, 140, 28, nanovgo.RGBA(0, 96, 128, 255)) y += 45 // Slider drawLabel(ctx, "Diameter", x, y, 280, 20) y += 25 drawEditBoxNum(ctx, "123.00", "px", x+180, y, 100, 28) drawSlider(ctx, 0.4, x, y, 170, 28) y += 55 drawButton(ctx, IconTRASH, "Delete", x, y, 160, 28, nanovgo.RGBA(128, 16, 8, 255)) drawButton(ctx, 0, "Cancel", x+170, y, 110, 28, nanovgo.RGBA(0, 0, 0, 0)) // Thumbnails box drawThumbnails(ctx, 365, popy-30, 160, 300, data.Images, t) }
func (i *ImageView) Draw(self Widget, ctx *nanovgo.Context) { if i.image == 0 { return } x := float32(i.x) y := float32(i.y) ow := float32(i.w) oh := float32(i.h) var w, h float32 { iw, ih, _ := ctx.ImageSize(i.image) w = float32(iw) h = float32(ih) } if i.policy == ImageSizePolicyFixed { if ow < w { h = float32(int(h * ow / w)) w = ow } if oh < h { w = float32(int(w * oh / h)) h = oh } } else { // mPolicy == Expand // expand to width h = float32(int(h * ow / w)) w = ow // shrink to height, if necessary if oh < h { w = float32(int(w * oh / h)) h = oh } } imgPaint := nanovgo.ImagePattern(x, y, w, h, 0, i.image, 1.0) ctx.BeginPath() ctx.Rect(x, y, w, h) ctx.SetFillPaint(imgPaint) ctx.Fill() }
func loadImageDirectory(ctx *nanovgo.Context, dir string) []nanogui.Image { var images []nanogui.Image files, err := AssetDir("icons") if err != nil { panic(err) } for _, file := range files { fullPath := fmt.Sprintf("%s/%s", "icons", file) img := ctx.CreateImageFromMemory(0, MustAsset(fullPath)) if img == 0 { panic("Could not open image data!") } images = append(images, nanogui.Image{ ImageID: img, Name: fullPath[:len(fullPath)-4], }) } return images }
func (t *TextBox) PreferredSize(self Widget, ctx *nanovgo.Context) (int, int) { sizeH := float32(t.FontSize()) * 1.4 var unitWidth, textWidth float32 ctx.SetFontSize(float32(t.FontSize())) if t.unitImage > 0 { w, h, _ := ctx.ImageSize(t.unitImage) unitHeight := sizeH * 0.4 unitWidth = float32(w) * unitHeight / float32(h) } else if t.units != "" { unitWidth, _ = ctx.TextBounds(0, 0, t.units) } textWidth, _ = ctx.TextBounds(0, 0, string(t.editingText())) sizeW := sizeH + textWidth + unitWidth return int(sizeW), int(sizeH) }
func (c *CheckBox) PreferredSize(self Widget, ctx *nanovgo.Context) (int, int) { fw, fh := c.FixedSize() if fw > 0 || fh > 0 { return fw, fh } fontSize := float32(c.FontSize()) ctx.SetFontSize(fontSize) ctx.SetFontFace(c.theme.FontNormal) w, _ := ctx.TextBounds(0, 0, c.caption) return int(w + 1.7*fontSize), int(fontSize * 1.3) }
func (w *Window) PreferredSize(self Widget, ctx *nanovgo.Context) (int, int) { if w.buttonPanel != nil { w.buttonPanel.SetVisible(false) } width, height := w.WidgetImplement.PreferredSize(self, ctx) if w.buttonPanel != nil { w.buttonPanel.SetVisible(true) } ctx.SetFontSize(18.0) ctx.SetFontFace(w.theme.FontBold) _, bounds := ctx.TextBounds(0, 0, w.title) return maxI(width, int(bounds[2]-bounds[0])+20), maxI(height, int(bounds[3]-bounds[1])) }
func NewStandardTheme(ctx *nanovgo.Context) *Theme { ctx.CreateFontFromMemory("sans", MustAsset("fonts/Roboto-Regular.ttf"), 0) ctx.CreateFontFromMemory("sans-bold", MustAsset("fonts/Roboto-Bold.ttf"), 0) ctx.CreateFontFromMemory("icons", MustAsset("fonts/entypo.ttf"), 0) return &Theme{ StandardFontSize: 16, ButtonFontSize: 20, TextBoxFontSize: 20, WindowCornerRadius: 2, WindowHeaderHeight: 30, WindowDropShadowSize: 10, ButtonCornerRadius: 2, DropShadow: nanovgo.MONO(0, 128), Transparent: nanovgo.MONO(0, 0), BorderDark: nanovgo.MONO(29, 255), BorderLight: nanovgo.MONO(92, 255), BorderMedium: nanovgo.MONO(35, 255), TextColor: nanovgo.MONO(255, 160), DisabledTextColor: nanovgo.MONO(255, 80), TextColorShadow: nanovgo.MONO(0, 160), IconColor: nanovgo.MONO(255, 160), ButtonGradientTopFocused: nanovgo.MONO(64, 255), ButtonGradientBotFocused: nanovgo.MONO(48, 255), ButtonGradientTopUnfocused: nanovgo.MONO(74, 255), ButtonGradientBotUnfocused: nanovgo.MONO(58, 255), ButtonGradientTopPushed: nanovgo.MONO(41, 255), ButtonGradientBotPushed: nanovgo.MONO(29, 255), WindowFillUnfocused: nanovgo.MONO(43, 230), WindowFillFocused: nanovgo.MONO(45, 230), WindowTitleUnfocused: nanovgo.MONO(220, 160), WindowTitleFocused: nanovgo.MONO(255, 190), WindowHeaderGradientTop: nanovgo.MONO(74, 255), WindowHeaderGradientBot: nanovgo.MONO(58, 255), WindowHeaderSepTop: nanovgo.MONO(92, 255), WindowHeaderSepBot: nanovgo.MONO(29, 255), WindowPopup: nanovgo.MONO(50, 255), WindowPopupTransparent: nanovgo.MONO(50, 0), FontNormal: "sans", FontBold: "sans-bold", FontIcons: "icons", } }
func LoadDemo(ctx *nanovgo.Context) *demo.DemoData { d := &demo.DemoData{} for i := 0; i < 12; i++ { path := fmt.Sprintf("assets/image%d.jpg", i+1) d.Images = append(d.Images, ctx.CreateImageFromMemory(0, demo.MustAsset(path))) if d.Images[i] == 0 { log.Fatalf("Could not load %s", path) } } d.FontIcons = ctx.CreateFontFromMemory("icons", demo.MustAsset("assets/entypo.ttf"), 0) if d.FontIcons == -1 { log.Fatalln("Could not add font icons.") } d.FontNormal = ctx.CreateFontFromMemory("sans", demo.MustAsset("assets/Roboto-Regular.ttf"), 0) if d.FontNormal == -1 { log.Fatalln("Could not add font italic.") } d.FontBold = ctx.CreateFontFromMemory("sans-bold", demo.MustAsset("assets/Roboto-Bold.ttf"), 0) if d.FontBold == -1 { log.Fatalln("Could not add font bold.") } return d }
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 (p *ProgressBar) Draw(self Widget, ctx *nanovgo.Context) { px := float32(p.x) py := float32(p.y) pw := float32(p.w) ph := float32(p.h) p.WidgetImplement.Draw(self, ctx) paint := nanovgo.BoxGradient(px+1, py+1, pw-2, ph, 3, 4, nanovgo.MONO(0, 32), nanovgo.MONO(0, 92)) ctx.BeginPath() ctx.RoundedRect(px, py, pw, ph, 3) ctx.SetFillPaint(paint) ctx.Fill() value := clampF(p.value, 0.0, 1.0) barPos := (pw - 2) * value barPaint := nanovgo.BoxGradient(px, py, barPos+1.5, ph-1, 3, 4, nanovgo.MONO(220, 100), nanovgo.MONO(128, 100)) ctx.BeginPath() ctx.RoundedRect(px+1, py+1, barPos, ph-2, 3) ctx.SetFillPaint(barPaint) ctx.Fill() }
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 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 (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() } }
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 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 (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 (p *Popup) Draw(self Widget, ctx *nanovgo.Context) { p.RefreshRelativePlacement() if !p.visible { return } ds := float32(p.theme.WindowDropShadowSize) cr := float32(p.theme.WindowCornerRadius) px := float32(p.x) py := float32(p.y) pw := float32(p.w) ph := float32(p.h) ah := float32(p.anchorHeight) /* Draw a drop shadow */ shadowPaint := nanovgo.BoxGradient(px, py, pw, ph, cr*2, ds*2, p.theme.DropShadow, p.theme.Transparent) ctx.BeginPath() ctx.Rect(px-ds, py-ds, pw+ds*2, ph+ds*2) ctx.RoundedRect(px, py, pw, ph, cr) ctx.PathWinding(nanovgo.Hole) ctx.SetFillPaint(shadowPaint) ctx.Fill() /* Draw window */ ctx.BeginPath() ctx.RoundedRect(px, py, pw, ph, cr) ctx.MoveTo(px-15, py+ah) ctx.LineTo(px+1, py+ah-15) ctx.LineTo(px+1, py+ah+15) ctx.SetFillColor(p.theme.WindowPopup) ctx.Fill() p.WidgetImplement.Draw(self, ctx) }
// 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 (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 (c *CheckBox) Draw(self Widget, ctx *nanovgo.Context) { cx := float32(c.x) cy := float32(c.y) ch := float32(c.h) c.WidgetImplement.Draw(self, ctx) fontSize := float32(c.FontSize()) ctx.SetFontSize(fontSize) ctx.SetFontFace(c.theme.FontNormal) if c.enabled { ctx.SetFillColor(c.theme.TextColor) } else { ctx.SetFillColor(c.theme.DisabledTextColor) } ctx.SetTextAlign(nanovgo.AlignLeft | nanovgo.AlignMiddle) ctx.Text(cx+1.2*ch+5, cy+ch*0.5, c.caption) var bgAlpha uint8 if c.pushed { bgAlpha = 100 } else { bgAlpha = 32 } bgPaint := nanovgo.BoxGradient(cx+1.5, cy+1.5, ch-2.0, ch-2.0, 3, 3, nanovgo.MONO(0, bgAlpha), nanovgo.MONO(0, 180)) ctx.BeginPath() ctx.RoundedRect(cx+1.0, cy+1.0, ch-2.0, ch-2.0, 3) ctx.SetFillPaint(bgPaint) ctx.Fill() if c.checked { ctx.SetFontSize(ch) ctx.SetFontFace(c.theme.FontIcons) if c.enabled { ctx.SetFillColor(c.theme.IconColor) } else { ctx.SetFillColor(c.theme.DisabledTextColor) } ctx.SetTextAlign(nanovgo.AlignCenter | nanovgo.AlignMiddle) ctx.Text(cx+ch*0.5+1.0, cy+ch*0.5, string([]rune{rune(IconCheck)})) } }
func drawParagraph(ctx *nanovgo.Context, x, y, width, height, mx, my float32) { text := "This is longer chunk of text.\n \n Would have used lorem ipsum but she was busy jumping over the lazy dog with the fox and all the men who came to the aid of the party." ctx.Save() defer ctx.Restore() ctx.SetFontSize(18.0) ctx.SetFontFace("sans") ctx.SetTextAlign(nanovgo.AlignLeft | nanovgo.AlignTop) _, _, lineh := ctx.TextMetrics() // The text break API can be used to fill a large buffer of rows, // or to iterate over the text just few lines (or just one) at a time. // The "next" variable of the last returned item tells where to continue. runes := []rune(text) var gx, gy float32 var gutter int lnum := 0 for _, row := range ctx.TextBreakLinesRune(runes, width) { hit := mx > x && mx < (x+width) && my >= y && my < (y+lineh) ctx.BeginPath() var alpha uint8 if hit { alpha = 64 } else { alpha = 16 } ctx.SetFillColor(nanovgo.RGBA(255, 255, 255, alpha)) ctx.Rect(x, y, row.Width, lineh) ctx.Fill() ctx.SetFillColor(nanovgo.RGBA(255, 255, 255, 255)) ctx.TextRune(x, y, runes[row.StartIndex:row.EndIndex]) if hit { var caretX float32 if mx < x+row.Width/2 { caretX = x } else { caretX = x + row.Width } px := x lineRune := runes[row.StartIndex:row.EndIndex] glyphs := ctx.TextGlyphPositionsRune(x, y, lineRune) for j, glyph := range glyphs { x0 := glyph.X var x1 float32 if j+1 < len(glyphs) { x1 = glyphs[j+1].X } else { x1 = x + row.Width } gx = x0*0.3 + x1*0.7 if mx >= px && mx < gx { caretX = glyph.X } px = gx } ctx.BeginPath() ctx.SetFillColor(nanovgo.RGBA(255, 192, 0, 255)) ctx.Rect(caretX, y, 1, lineh) ctx.Fill() gutter = lnum + 1 gx = x - 10 gy = y + lineh/2 } lnum++ y += lineh } if gutter > 0 { txt := strconv.Itoa(gutter) ctx.SetFontSize(13.0) ctx.SetTextAlign(nanovgo.AlignRight | nanovgo.AlignMiddle) _, bounds := ctx.TextBounds(gx, gy, txt) ctx.BeginPath() ctx.SetFillColor(nanovgo.RGBA(255, 192, 0, 255)) ctx.RoundedRect( float32(int(bounds[0]-4)), float32(int(bounds[1]-2)), float32(int(bounds[2]-bounds[0])+8), float32(int(bounds[3]-bounds[1])+4), float32(int(bounds[3]-bounds[1])+4)/2.0-1.0) ctx.Fill() ctx.SetFillColor(nanovgo.RGBA(32, 32, 32, 255)) ctx.Text(gx, gy, txt) } y += 20.0 ctx.SetFontSize(13.0) ctx.SetTextAlign(nanovgo.AlignLeft | nanovgo.AlignTop) ctx.SetTextLineHeight(1.2) bounds := ctx.TextBoxBounds(x, y, 150, "Hover your mouse over the text to see calculated caret position.") // Fade the tooltip out when close to it. gx = absF((mx - (bounds[0]+bounds[2])*0.5) / (bounds[0] - bounds[2])) gy = absF((my - (bounds[1]+bounds[3])*0.5) / (bounds[1] - bounds[3])) a := maxF(gx, gy) - 0.5 a = clampF(a, 0, 1) ctx.SetGlobalAlpha(a) ctx.BeginPath() ctx.SetFillColor(nanovgo.RGBA(220, 220, 220, 255)) ctx.RoundedRect(bounds[0]-2, bounds[1]-2, float32(int(bounds[2]-bounds[0])+4), float32(int(bounds[3]-bounds[1])+4), 3) px := float32(int((bounds[2] + bounds[0]) / 2)) ctx.MoveTo(px, bounds[1]-10) ctx.LineTo(px+7, bounds[1]+1) ctx.LineTo(px-7, bounds[1]+1) ctx.Fill() ctx.SetFillColor(nanovgo.RGBA(0, 0, 0, 220)) ctx.TextBox(x, y, 150, "Hover your mouse over the text to see calculated caret position.") }
func (p *PopupButton) Draw(self Widget, ctx *nanovgo.Context) { if !p.enabled && p.pushed { p.pushed = false } p.popup.SetVisible(p.pushed) p.Button.Draw(self, ctx) if p.chevronIcon != 0 { ctx.SetFillColor(p.TextColor()) ctx.SetFontSize(float32(p.FontSize())) ctx.SetFontFace(p.theme.FontIcons) ctx.SetTextAlign(nanovgo.AlignMiddle | nanovgo.AlignLeft) fontString := string([]rune{rune(p.chevronIcon)}) iw, _ := ctx.TextBounds(0, 0, fontString) px, py := p.Position() w, h := p.Size() ix := px + w - int(iw) - 8 iy := py + h/2 - 1 ctx.Text(float32(ix), float32(iy), fontString) } }
func LoadFontAs(ctx *nanovgo.Context, name string) { ctx.CreateFontFromMemory(name, MustAsset("font/MaterialIcons-Regular.ttf"), 0) }
func LoadFont(ctx *nanovgo.Context) { ctx.CreateFontFromMemory("materialicons", MustAsset("font/MaterialIcons-Regular.ttf"), 0) }
// RenderGraph shows graph func (pg *PerfGraph) RenderGraph(ctx *nanovgo.Context, x, y float32) { avg := pg.GetGraphAverage() var w float32 = 200 var h float32 = 35 ctx.BeginPath() ctx.Rect(x, y, w, h) ctx.SetFillColor(backgroundColor) ctx.Fill() ctx.BeginPath() ctx.MoveTo(x, y+h) for i := 0; i < nvgGraphHistoryCount; i++ { v := float32(1.0) / float32(0.00001+pg.values[(pg.head+i)%nvgGraphHistoryCount]) if v > 80.0 { v = 80.0 } vx := x + float32(i)/float32(nvgGraphHistoryCount-1)*w vy := y + h - ((v / 80.0) * h) ctx.LineTo(vx, vy) } ctx.LineTo(x+w, y+h) ctx.SetFillColor(graphColor) ctx.Fill() ctx.SetFontFace(pg.fontFace) if len(pg.name) > 0 { ctx.SetFontSize(14.0) ctx.SetTextAlign(nanovgo.AlignLeft | nanovgo.AlignTop) ctx.SetFillColor(titleTextColor) ctx.Text(x+3, y+1, pg.name) } ctx.SetFontSize(18.0) ctx.SetTextAlign(nanovgo.AlignRight | nanovgo.AlignTop) ctx.SetFillColor(fpsTextColor) ctx.Text(x+w-3, y+1, fmt.Sprintf("%.2f FPS", 1.0/avg)) ctx.SetFontSize(15.0) ctx.SetTextAlign(nanovgo.AlignRight | nanovgo.AlignBottom) ctx.SetFillColor(averageTextColor) ctx.Text(x+w-3, y+h+1, fmt.Sprintf("%.2f ms", avg*1000.0)) }
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() } }