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 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 (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 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 (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 drawEditBoxNum(ctx *nanovgo.Context, text, units string, x, y, w, h float32) { drawEditBoxBase(ctx, x, y, w, h) uw, _ := ctx.TextBounds(0, 0, units) ctx.SetFontSize(18.0) ctx.SetFontFace("sans") ctx.SetFillColor(nanovgo.RGBA(255, 255, 255, 64)) ctx.SetTextAlign(nanovgo.AlignRight | nanovgo.AlignMiddle) ctx.Text(x+w-h*0.3, y+h*0.5, units) ctx.SetFontSize(20.0) ctx.SetFontFace("sans") ctx.SetFillColor(nanovgo.RGBA(255, 255, 255, 128)) ctx.SetTextAlign(nanovgo.AlignRight | nanovgo.AlignMiddle) ctx.Text(x+w-uw-h*0.5, y+h*0.5, text) }
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 (l *Label) Draw(self Widget, ctx *nanovgo.Context) { l.WidgetImplement.Draw(self, ctx) ctx.SetFontSize(float32(l.FontSize())) ctx.SetFontFace(l.Font()) ctx.SetFillColor(l.color) width := 0 if l.FixedWidth() > 0 { width = l.FixedWidth() } else if l.columnWidth > 0 && l.wrap { width = l.columnWidth } if width > 0 { ctx.SetTextAlign(nanovgo.AlignLeft | nanovgo.AlignTop) ctx.TextBox(float32(l.x), float32(l.y), float32(width), l.caption) } else { ctx.SetTextAlign(nanovgo.AlignLeft | nanovgo.AlignMiddle) ctx.Text(float32(l.x), float32(l.y)+float32(l.h)*0.5, l.caption) } }
func drawCheckBox(ctx *nanovgo.Context, text string, x, y, w, h float32) { ctx.SetFontSize(18.0) ctx.SetFontFace("sans") ctx.SetFillColor(nanovgo.RGBA(255, 255, 255, 160)) ctx.SetTextAlign(nanovgo.AlignLeft | nanovgo.AlignMiddle) ctx.Text(x+28, y+h*0.5, text) bg := nanovgo.BoxGradient(x+1, y+float32(int(h*0.5))-9+1, 18, 18, 3, 3, nanovgo.RGBA(0, 0, 0, 32), nanovgo.RGBA(0, 0, 0, 92)) ctx.BeginPath() ctx.RoundedRect(x+1, y+float32(int(h*0.5))-9, 18, 18, 3) ctx.SetFillPaint(bg) ctx.Fill() ctx.SetFontSize(40) ctx.SetFontFace("icons") ctx.SetFillColor(nanovgo.RGBA(255, 255, 255, 128)) ctx.SetTextAlign(nanovgo.AlignCenter | nanovgo.AlignMiddle) ctx.Text(x+9+2, y+h*0.5, cpToUTF8(IconCHECK)) }
func drawSearchBox(ctx *nanovgo.Context, text string, x, y, w, h float32) { cornerRadius := h/2 - 1 // Edit bg := nanovgo.BoxGradient(x, y+1.5, w, h, h/2, 5, nanovgo.RGBA(0, 0, 0, 16), nanovgo.RGBA(0, 0, 0, 92)) ctx.BeginPath() ctx.RoundedRect(x, y, w, h, cornerRadius) ctx.SetFillPaint(bg) ctx.Fill() /* ctx.BeginPath(); ctx.RoundedRect(x+0.5f,y+0.5f, w-1,h-1, cornerRadius-0.5f); ctx.StrokeColor(ctx.RGBA(0,0,0,48)); ctx.Stroke();*/ 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+h*0.55, y+h*0.55, cpToUTF8(IconSEARCH)) ctx.SetFontSize(20.0) ctx.SetFontFace("sans") ctx.SetFillColor(nanovgo.RGBA(255, 255, 255, 32)) ctx.SetTextAlign(nanovgo.AlignLeft | nanovgo.AlignMiddle) ctx.Text(x+h*1.05, y+h*0.5, text) ctx.SetFontSize(h * 1.3) ctx.SetFontFace("icons") ctx.SetFillColor(nanovgo.RGBA(255, 255, 255, 32)) ctx.SetTextAlign(nanovgo.AlignCenter | nanovgo.AlignMiddle) ctx.Text(x+w-h*0.55, y+h*0.55, cpToUTF8(IconCIRCLEDCROSS)) }
func (b *Button) PreferredSize(self Widget, ctx *nanovgo.Context) (int, int) { fontSize := float32(b.FontSize()) ctx.SetFontSize(fontSize) ctx.SetFontFace(b.theme.FontBold) tw, _ := ctx.TextBounds(0, 0, b.caption) var iw float32 ih := fontSize if b.icon > 0 { ih *= 1.5 / 2 ctx.SetFontFace(b.theme.FontIcons) ctx.SetFontSize(ih) iw, _ = ctx.TextBounds(0, 0, string([]rune{rune(b.icon)})) iw += float32(b.y) * 0.15 } else if b.imageIcon > 0 { ih *= 0.9 w, h, _ := ctx.ImageSize(b.imageIcon) iw = float32(w) * ih / float32(h) } return int(tw + iw + 20), int(fontSize) + 10 }
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 (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 (l *Label) PreferredSize(self Widget, ctx *nanovgo.Context) (int, int) { if l.caption == "" { return 0, 0 } ctx.SetFontSize(float32(l.FontSize())) ctx.SetFontFace(l.Font()) width := 0 if l.FixedWidth() > 0 { width = l.FixedWidth() } else if l.columnWidth > 0 && l.wrap { width = l.columnWidth } if width > 0 { ctx.SetTextAlign(nanovgo.AlignLeft | nanovgo.AlignTop) bounds := ctx.TextBoxBounds(0, 0, float32(width), l.caption) return width, int(bounds[3] - bounds[1]) } else { ctx.SetTextAlign(nanovgo.AlignLeft | nanovgo.AlignTop) w, _ := ctx.TextBounds(0, 0, l.caption) return int(w), l.Theme().StandardFontSize } }
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) }
// 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 (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) }
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 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.") }